248 lines
11 KiB
TypeScript
Raw Normal View History

// (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 { NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events';
import { CoreInitDelegate } from '@providers/init';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreLoginHelperProvider } from '../../login/providers/helper';
import { CoreContentLinksDelegate, CoreContentLinksAction } from './delegate';
import { CoreConstants } from '../../constants';
import { CoreConfigConstants } from '../../../configconstants';
import { CoreSitePluginsProvider } from '../../siteplugins/providers/siteplugins';
/**
* Service that provides some features regarding content links.
*/
@Injectable()
export class CoreContentLinksHelperProvider {
protected logger;
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private loginHelper: CoreLoginHelperProvider,
private contentLinksDelegate: CoreContentLinksDelegate, private appProvider: CoreAppProvider,
private domUtils: CoreDomUtilsProvider, private urlUtils: CoreUrlUtilsProvider, private translate: TranslateService,
private initDelegate: CoreInitDelegate, eventsProvider: CoreEventsProvider, private textUtils: CoreTextUtilsProvider,
private sitePluginsProvider: CoreSitePluginsProvider) {
this.logger = logger.getInstance('CoreContentLinksHelperProvider');
// Listen for app launched URLs. If we receive one, check if it's a content link.
eventsProvider.on(CoreEventsProvider.APP_LAUNCHED_URL, this.handleCustomUrl.bind(this));
}
/**
* Get the first valid action in a list of actions.
*
* @param {CoreContentLinksAction[]} actions List of actions.
* @return {CoreContentLinksAction} First valid action. Returns undefined if no valid action found.
*/
2018-01-29 10:05:20 +01:00
getFirstValidAction(actions: CoreContentLinksAction[]): CoreContentLinksAction {
if (actions) {
for (let i = 0; i < actions.length; i++) {
const action = actions[i];
if (action && action.sites && action.sites.length) {
return action;
}
}
}
}
/**
* Goes to a certain page in a certain site. If the site is current site it will perform a regular navigation,
* otherwise it will 'redirect' to the other site.
*
* @param {NavController} navCtrl The NavController instance to use.
* @param {string} pageName Name of the page to go.
* @param {any} [pageParams] Params to send to the page.
* @param {string} [siteId] Site ID. If not defined, current site.
*/
2018-01-29 10:05:20 +01:00
goInSite(navCtrl: NavController, pageName: string, pageParams: any, siteId?: string): void {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (navCtrl && siteId == this.sitesProvider.getCurrentSiteId()) {
navCtrl.push(pageName, pageParams);
} else {
this.loginHelper.redirect(pageName, pageParams, siteId);
}
}
/**
* Go to the page to choose a site.
*
* @param {string} url URL to treat.
*/
2018-01-29 10:05:20 +01:00
goToChooseSite(url: string): void {
this.appProvider.getRootNavController().setRoot('CoreContentLinksChooseSitePage', { url: url });
}
/**
* Handle a URL received by Custom URL Scheme.
*
* @param {string} url URL to handle.
* @return {boolean} True if the URL should be handled by this component, false otherwise.
*/
2018-01-29 10:05:20 +01:00
handleCustomUrl(url: string): boolean {
const contentLinksScheme = CoreConfigConstants.customurlscheme + '://link';
if (url.indexOf(contentLinksScheme) == -1) {
return false;
}
2018-01-29 10:05:20 +01:00
const modal = this.domUtils.showModalLoading();
let username;
url = this.textUtils.decodeURIComponent(url);
// App opened using custom URL scheme.
this.logger.debug('Treating custom URL scheme: ' + url);
// Delete the scheme from the URL.
url = url.replace(contentLinksScheme + '=', '');
// Detect if there's a user specified.
username = this.urlUtils.getUsernameFromUrl(url);
if (username) {
url = url.replace(username + '@', ''); // Remove the username from the URL.
}
// Wait for the app to be ready.
this.initDelegate.ready().then(() => {
// Check if the site is stored.
return this.sitesProvider.getSiteIdsFromUrl(url, false, username);
}).then((siteIds) => {
if (siteIds.length) {
modal.dismiss(); // Dismiss modal so it doesn't collide with confirms.
2018-01-29 10:05:20 +01:00
return this.handleLink(url, username).then((treated) => {
if (!treated) {
this.domUtils.showErrorModal('core.contentlinks.errornoactions', true);
}
});
} else {
// Get the site URL.
const siteUrl = this.contentLinksDelegate.getSiteUrl(url);
if (!siteUrl) {
this.domUtils.showErrorModal('core.login.invalidsite', true);
2018-01-29 10:05:20 +01:00
return;
}
// Check that site exists.
return this.sitesProvider.checkSite(siteUrl).then((result) => {
// Site exists. We'll allow to add it.
2018-01-29 10:05:20 +01:00
const ssoNeeded = this.loginHelper.isSSOLoginNeeded(result.code),
pageName = 'CoreLoginCredentialsPage',
pageParams = {
siteUrl: result.siteUrl,
username: username,
urlToOpen: url,
siteConfig: result.config
};
let promise,
hasSitePluginsLoaded = false;
modal.dismiss(); // Dismiss modal so it doesn't collide with confirms.
if (!this.sitesProvider.isLoggedIn()) {
// Not logged in, no need to confirm. If SSO the confirm will be shown later.
promise = Promise.resolve();
} else {
// Ask the user before changing site.
const confirmMsg = this.translate.instant('core.contentlinks.confirmurlothersite');
promise = this.domUtils.showConfirm(confirmMsg).then(() => {
if (!ssoNeeded) {
hasSitePluginsLoaded = this.sitePluginsProvider.hasSitePluginsLoaded;
if (hasSitePluginsLoaded) {
// Store the redirect since logout will restart the app.
this.appProvider.storeRedirect(CoreConstants.NO_SITE_ID, pageName, pageParams);
}
return this.sitesProvider.logout().catch(() => {
// Ignore errors (shouldn't happen).
});
}
});
}
return promise.then(() => {
if (ssoNeeded) {
this.loginHelper.confirmAndOpenBrowserForSSOLogin(
2018-01-29 10:05:20 +01:00
result.siteUrl, result.code, result.service, result.config && result.config.launchurl);
} else if (!hasSitePluginsLoaded) {
this.appProvider.getRootNavController().setRoot(pageName, pageParams);
}
});
}).catch((error) => {
if (error) {
this.domUtils.showErrorModal(error);
}
});
}
}).finally(() => {
modal.dismiss();
});
return true;
}
/**
* Handle a link.
*
* @param {string} url URL to handle.
* @param {string} [username] Username related with the URL. E.g. in 'http://myuser@m.com', url would be 'http://m.com' and
* the username 'myuser'. Don't use it if you don't want to filter by username.
* @param {NavController} [navCtrl] Nav Controller to use to navigate.
* @return {Promise<boolean>} Promise resolved with a boolean: true if URL was treated, false otherwise.
*/
2018-01-29 10:05:20 +01:00
handleLink(url: string, username?: string, navCtrl?: NavController): Promise<boolean> {
// Check if the link should be treated by some component/addon.
return this.contentLinksDelegate.getActionsFor(url, undefined, username).then((actions) => {
const action = this.getFirstValidAction(actions);
if (action) {
if (!this.sitesProvider.isLoggedIn()) {
// No current site. Perform the action if only 1 site found, choose the site otherwise.
if (action.sites.length == 1) {
action.action(action.sites[0], navCtrl);
} else {
this.goToChooseSite(url);
}
} else if (action.sites.length == 1 && action.sites[0] == this.sitesProvider.getCurrentSiteId()) {
// Current site.
action.action(action.sites[0], navCtrl);
} else {
// Not current site or more than one site. Ask for confirmation.
this.domUtils.showConfirm(this.translate.instant('core.contentlinks.confirmurlothersite')).then(() => {
if (action.sites.length == 1) {
action.action(action.sites[0], navCtrl);
} else {
this.goToChooseSite(url);
}
});
}
2018-01-29 10:05:20 +01:00
return true;
}
2018-01-29 10:05:20 +01:00
return false;
}).catch(() => {
return false;
});
}
}