2018-01-22 10:28:27 +01:00
|
|
|
// (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';
|
2018-01-31 15:17:41 +01:00
|
|
|
import { CoreTextUtilsProvider } from '../../../providers/utils/text';
|
2018-01-22 10:28:27 +01:00
|
|
|
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';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
2018-01-31 15:17:41 +01:00
|
|
|
private initDelegate: CoreInitDelegate, eventsProvider: CoreEventsProvider, private textUtils: CoreTextUtilsProvider) {
|
2018-01-22 10:28:27 +01:00
|
|
|
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 {
|
2018-01-22 10:28:27 +01:00
|
|
|
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 {
|
2018-01-22 10:28:27 +01:00
|
|
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
2018-01-25 13:19:11 +01:00
|
|
|
if (navCtrl && siteId == this.sitesProvider.getCurrentSiteId()) {
|
2018-01-22 10:28:27 +01:00
|
|
|
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 });
|
2018-01-22 10:28:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 {
|
2018-01-22 10:28:27 +01:00
|
|
|
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;
|
|
|
|
|
2018-01-31 15:17:41 +01:00
|
|
|
url = this.textUtils.decodeURIComponent(url);
|
2018-01-22 10:28:27 +01:00
|
|
|
|
|
|
|
// 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
|
|
|
|
2018-01-22 10:28:27 +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
|
|
|
|
2018-01-22 10:28:27 +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),
|
2018-01-22 10:28:27 +01:00
|
|
|
hasRemoteAddonsLoaded = false,
|
|
|
|
pageName = 'CoreLoginCredentialsPage',
|
|
|
|
pageParams = {
|
|
|
|
siteUrl: result.siteUrl,
|
|
|
|
username: username,
|
|
|
|
urlToOpen: url,
|
|
|
|
siteConfig: result.config
|
|
|
|
};
|
2018-01-29 10:05:20 +01:00
|
|
|
let promise;
|
2018-01-22 10:28:27 +01:00
|
|
|
|
|
|
|
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) {
|
2018-01-29 10:05:20 +01:00
|
|
|
// @todo hasRemoteAddonsLoaded = $mmAddonManager.hasRemoteAddonsLoaded(); @todo
|
2018-01-22 10:28:27 +01:00
|
|
|
if (hasRemoteAddonsLoaded) {
|
|
|
|
// 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);
|
2018-01-22 10:28:27 +01:00
|
|
|
} else if (!hasRemoteAddonsLoaded) {
|
|
|
|
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.
|
2018-01-23 11:26:21 +01:00
|
|
|
* @param {NavController} [navCtrl] Nav Controller to use to navigate.
|
2018-01-22 10:28:27 +01:00
|
|
|
* @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> {
|
2018-01-22 10:28:27 +01:00
|
|
|
// 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) {
|
2018-01-23 11:26:21 +01:00
|
|
|
action.action(action.sites[0], navCtrl);
|
2018-01-22 10:28:27 +01:00
|
|
|
} else {
|
|
|
|
this.goToChooseSite(url);
|
|
|
|
}
|
|
|
|
} else if (action.sites.length == 1 && action.sites[0] == this.sitesProvider.getCurrentSiteId()) {
|
|
|
|
// Current site.
|
2018-01-23 11:26:21 +01:00
|
|
|
action.action(action.sites[0], navCtrl);
|
2018-01-22 10:28:27 +01:00
|
|
|
} 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) {
|
2018-01-23 11:26:21 +01:00
|
|
|
action.action(action.sites[0], navCtrl);
|
2018-01-22 10:28:27 +01:00
|
|
|
} else {
|
|
|
|
this.goToChooseSite(url);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2018-01-29 10:05:20 +01:00
|
|
|
|
2018-01-22 10:28:27 +01:00
|
|
|
return true;
|
|
|
|
}
|
2018-01-29 10:05:20 +01:00
|
|
|
|
2018-01-22 10:28:27 +01:00
|
|
|
return false;
|
|
|
|
}).catch(() => {
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|