commit
4c7841359a
|
@ -38,7 +38,7 @@ import { CorePromiseUtils } from '@singletons/promise-utils';
|
||||||
})
|
})
|
||||||
export class AddonModForumSearchPage implements OnInit {
|
export class AddonModForumSearchPage implements OnInit {
|
||||||
|
|
||||||
loadMoreError: string | null = null;
|
loadMoreError = false;
|
||||||
searchBanner: string | null = null;
|
searchBanner: string | null = null;
|
||||||
resultsSource = new CoreSearchGlobalSearchResultsSource('', {});
|
resultsSource = new CoreSearchGlobalSearchResultsSource('', {});
|
||||||
forum?: AddonModForumData;
|
forum?: AddonModForumData;
|
||||||
|
@ -128,7 +128,7 @@ export class AddonModForumSearchPage implements OnInit {
|
||||||
* Clear search results.
|
* Clear search results.
|
||||||
*/
|
*/
|
||||||
clearSearch(): void {
|
clearSearch(): void {
|
||||||
this.loadMoreError = null;
|
this.loadMoreError = false;
|
||||||
|
|
||||||
this.resultsSource.setQuery('');
|
this.resultsSource.setQuery('');
|
||||||
this.resultsSource.reset();
|
this.resultsSource.reset();
|
||||||
|
@ -152,7 +152,7 @@ export class AddonModForumSearchPage implements OnInit {
|
||||||
try {
|
try {
|
||||||
await this.resultsSource?.load();
|
await this.resultsSource?.load();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.loadMoreError = CoreDomUtils.getErrorMessage(error);
|
this.loadMoreError = true;
|
||||||
} finally {
|
} finally {
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,14 +24,26 @@ import { CoreErrorObject } from '@services/error-helper';
|
||||||
*/
|
*/
|
||||||
export class CoreError extends Error {
|
export class CoreError extends Error {
|
||||||
|
|
||||||
constructor(message?: string) {
|
debug?: CoreErrorDebug;
|
||||||
|
|
||||||
|
constructor(message?: string, debug?: CoreErrorDebug) {
|
||||||
super(message);
|
super(message);
|
||||||
|
|
||||||
// Fix prototype chain: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
|
// Fix prototype chain: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
|
||||||
this.name = new.target.name;
|
this.name = new.target.name;
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
Object.setPrototypeOf(this, new.target.prototype);
|
||||||
|
|
||||||
|
this.debug = debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug information of the error.
|
||||||
|
*/
|
||||||
|
export type CoreErrorDebug = {
|
||||||
|
code?: string; // Technical error code useful for technical assistance.
|
||||||
|
details: string; // Technical error details useful for technical assistance.
|
||||||
|
};
|
||||||
|
|
||||||
export type CoreAnyError = string | CoreError | CoreErrorObject | null | undefined;
|
export type CoreAnyError = string | CoreError | CoreErrorObject | null | undefined;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError, CoreErrorDebug } from '@classes/errors/error';
|
||||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +20,7 @@ import { CoreUserSupportConfig } from '@features/user/classes/support/support-co
|
||||||
*/
|
*/
|
||||||
export class CoreSiteError extends CoreError {
|
export class CoreSiteError extends CoreError {
|
||||||
|
|
||||||
debug?: CoreSiteErrorDebug;
|
debug?: CoreErrorDebug;
|
||||||
supportConfig?: CoreUserSupportConfig;
|
supportConfig?: CoreUserSupportConfig;
|
||||||
|
|
||||||
constructor(options: CoreSiteErrorOptions) {
|
constructor(options: CoreSiteErrorOptions) {
|
||||||
|
@ -43,16 +43,11 @@ export class CoreSiteError extends CoreError {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CoreSiteErrorDebug = {
|
|
||||||
code: string; // Technical error code useful for technical assistance.
|
|
||||||
details: string; // Technical error details useful for technical assistance.
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CoreSiteErrorOptions = {
|
export type CoreSiteErrorOptions = {
|
||||||
message: string;
|
message: string;
|
||||||
|
|
||||||
// Debugging information.
|
// Debugging information.
|
||||||
debug?: CoreSiteErrorDebug;
|
debug?: CoreErrorDebug;
|
||||||
|
|
||||||
// Configuration to use to contact site support. If this attribute is present, it means
|
// Configuration to use to contact site support. If this attribute is present, it means
|
||||||
// that the error warrants contacting support.
|
// that the error warrants contacting support.
|
||||||
|
|
|
@ -181,7 +181,7 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!this.siteCheck) {
|
if (!this.siteCheck) {
|
||||||
this.siteCheck = await CoreSites.checkSite(this.site.siteUrl, protocol);
|
this.siteCheck = await CoreSites.checkSite(this.site.siteUrl, protocol, 'Credentials page');
|
||||||
this.siteCheck.config && this.site.setPublicConfig(this.siteCheck.config);
|
this.siteCheck.config && this.site.setPublicConfig(this.siteCheck.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import {
|
||||||
CoreLoginSiteFinderSettings,
|
CoreLoginSiteFinderSettings,
|
||||||
CoreLoginSiteSelectorListMethod,
|
CoreLoginSiteSelectorListMethod,
|
||||||
} from '@features/login/services/login-helper';
|
} from '@features/login/services/login-helper';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError, CoreErrorDebug } from '@classes/errors/error';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||||
|
@ -34,7 +34,7 @@ import { CoreCustomURLSchemes, CoreCustomURLSchemesHandleError } from '@services
|
||||||
import { CoreErrorHelper } from '@services/error-helper';
|
import { CoreErrorHelper } from '@services/error-helper';
|
||||||
import { CoreForms } from '@singletons/form';
|
import { CoreForms } from '@singletons/form';
|
||||||
import { AlertButton } from '@ionic/core';
|
import { AlertButton } from '@ionic/core';
|
||||||
import { CoreSiteError, CoreSiteErrorDebug } from '@classes/errors/siteerror';
|
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||||
import { CoreUserSupport } from '@features/user/services/support';
|
import { CoreUserSupport } from '@features/user/services/support';
|
||||||
import { CoreErrorAccordion } from '@services/error-accordion';
|
import { CoreErrorAccordion } from '@services/error-accordion';
|
||||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||||
|
@ -333,14 +333,14 @@ export class CoreLoginSitePage implements OnInit {
|
||||||
let checkResult: CoreSiteCheckResponse;
|
let checkResult: CoreSiteCheckResponse;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
checkResult = await CoreSites.checkSite(url);
|
checkResult = await CoreSites.checkSite(url, undefined, 'Site URL page');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Attempt guessing the domain if the initial check failed
|
// Attempt guessing the domain if the initial check failed
|
||||||
const domain = CoreUrl.guessMoodleDomain(url);
|
const domain = CoreUrl.guessMoodleDomain(url);
|
||||||
|
|
||||||
if (domain && domain != url) {
|
if (domain && domain != url) {
|
||||||
try {
|
try {
|
||||||
checkResult = await CoreSites.checkSite(domain);
|
checkResult = await CoreSites.checkSite(domain, undefined, 'Site URL page');
|
||||||
} catch (secondError) {
|
} catch (secondError) {
|
||||||
// Try to use the first error.
|
// Try to use the first error.
|
||||||
modal.dismiss();
|
modal.dismiss();
|
||||||
|
@ -419,7 +419,7 @@ export class CoreLoginSitePage implements OnInit {
|
||||||
*/
|
*/
|
||||||
protected async showLoginIssue(url: string, error: CoreError): Promise<void> {
|
protected async showLoginIssue(url: string, error: CoreError): Promise<void> {
|
||||||
let errorMessage = CoreDomUtils.getErrorMessage(error);
|
let errorMessage = CoreDomUtils.getErrorMessage(error);
|
||||||
let debug: CoreSiteErrorDebug | undefined;
|
let debug: CoreErrorDebug | undefined;
|
||||||
let errorTitle: string | undefined;
|
let errorTitle: string | undefined;
|
||||||
let site: CoreUnauthenticatedSite | undefined;
|
let site: CoreUnauthenticatedSite | undefined;
|
||||||
let supportConfig: CoreUserSupportConfig | undefined;
|
let supportConfig: CoreUserSupportConfig | undefined;
|
||||||
|
@ -480,7 +480,7 @@ export class CoreLoginSitePage implements OnInit {
|
||||||
const containerElement = alertElement.querySelector('.core-error-accordion-container');
|
const containerElement = alertElement.querySelector('.core-error-accordion-container');
|
||||||
|
|
||||||
if (containerElement) {
|
if (containerElement) {
|
||||||
await CoreErrorAccordion.render(containerElement, debug.code, debug.details);
|
await CoreErrorAccordion.render(containerElement, debug.details, debug.code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -608,7 +608,7 @@ export class CoreLoginSitePage implements OnInit {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if site uses SSO.
|
// Check if site uses SSO.
|
||||||
const siteCheck = await CoreSites.checkSite(siteUrl);
|
const siteCheck = await CoreSites.checkSite(siteUrl, undefined, 'Site URL page');
|
||||||
|
|
||||||
await CoreSites.checkApplication(siteCheck.config);
|
await CoreSites.checkApplication(siteCheck.config);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { CoreText } from '@singletons/text';
|
||||||
import { CoreObject } from '@singletons/object';
|
import { CoreObject } from '@singletons/object';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
import { CoreSite } from '@classes/sites/site';
|
import { CoreSite } from '@classes/sites/site';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError, CoreErrorDebug } from '@classes/errors/error';
|
||||||
import { CoreWSError } from '@classes/errors/wserror';
|
import { CoreWSError } from '@classes/errors/wserror';
|
||||||
import { DomSanitizer, makeSingleton, Translate } from '@singletons';
|
import { DomSanitizer, makeSingleton, Translate } from '@singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
@ -57,7 +57,7 @@ import {
|
||||||
IDENTITY_PROVIDER_FEATURE_NAME_PREFIX,
|
IDENTITY_PROVIDER_FEATURE_NAME_PREFIX,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import { LazyRoutesModule } from '@/app/app-routing.module';
|
import { LazyRoutesModule } from '@/app/app-routing.module';
|
||||||
import { CoreSiteError, CoreSiteErrorDebug } from '@classes/errors/siteerror';
|
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||||
import { CoreQRScan } from '@services/qrscan';
|
import { CoreQRScan } from '@services/qrscan';
|
||||||
import { CoreLoadings } from '@services/loadings';
|
import { CoreLoadings } from '@services/loadings';
|
||||||
import { CoreErrorHelper } from '@services/error-helper';
|
import { CoreErrorHelper } from '@services/error-helper';
|
||||||
|
@ -949,7 +949,7 @@ export class CoreLoginHelperProvider {
|
||||||
* @param site Site instance.
|
* @param site Site instance.
|
||||||
* @param debug Error debug information.
|
* @param debug Error debug information.
|
||||||
*/
|
*/
|
||||||
async showAppUnsupportedModal(siteUrl: string, site?: CoreUnauthenticatedSite, debug?: CoreSiteErrorDebug): Promise<void> {
|
async showAppUnsupportedModal(siteUrl: string, site?: CoreUnauthenticatedSite, debug?: CoreErrorDebug): Promise<void> {
|
||||||
const siteName = await site?.getSiteName() ?? siteUrl;
|
const siteName = await site?.getSiteName() ?? siteUrl;
|
||||||
|
|
||||||
await CoreDomUtils.showAlertWithOptions({
|
await CoreDomUtils.showAlertWithOptions({
|
||||||
|
@ -974,7 +974,7 @@ export class CoreLoginHelperProvider {
|
||||||
* @param siteUrl Site url.
|
* @param siteUrl Site url.
|
||||||
* @param debug Error debug information.
|
* @param debug Error debug information.
|
||||||
*/
|
*/
|
||||||
async openInBrowserFallback(siteUrl: string, debug?: CoreSiteErrorDebug): Promise<void> {
|
async openInBrowserFallback(siteUrl: string, debug?: CoreErrorDebug): Promise<void> {
|
||||||
CoreEvents.trigger(APP_UNSUPPORTED_CHURN, { siteUrl, debug });
|
CoreEvents.trigger(APP_UNSUPPORTED_CHURN, { siteUrl, debug });
|
||||||
|
|
||||||
await CoreOpener.openInBrowser(siteUrl, { showBrowserWarning: false });
|
await CoreOpener.openInBrowser(siteUrl, { showBrowserWarning: false });
|
||||||
|
@ -1677,7 +1677,7 @@ declare module '@singletons/events' {
|
||||||
*/
|
*/
|
||||||
export interface CoreEventsData {
|
export interface CoreEventsData {
|
||||||
[ALWAYS_SHOW_LOGIN_FORM_CHANGED]: { value: number };
|
[ALWAYS_SHOW_LOGIN_FORM_CHANGED]: { value: number };
|
||||||
[APP_UNSUPPORTED_CHURN]: { siteUrl: string; debug?: CoreSiteErrorDebug };
|
[APP_UNSUPPORTED_CHURN]: { siteUrl: string; debug?: CoreErrorDebug };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ import { CorePromiseUtils } from '@singletons/promise-utils';
|
||||||
export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewInit {
|
export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
courseId: number | null = null;
|
courseId: number | null = null;
|
||||||
loadMoreError: string | null = null;
|
loadMoreError = false;
|
||||||
searchBanner: string | null = null;
|
searchBanner: string | null = null;
|
||||||
resultsSource = new CoreSearchGlobalSearchResultsSource('', {});
|
resultsSource = new CoreSearchGlobalSearchResultsSource('', {});
|
||||||
private filtersObserver?: CoreEventObserver;
|
private filtersObserver?: CoreEventObserver;
|
||||||
|
@ -128,7 +128,7 @@ export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewI
|
||||||
* Clear search results.
|
* Clear search results.
|
||||||
*/
|
*/
|
||||||
clearSearch(): void {
|
clearSearch(): void {
|
||||||
this.loadMoreError = null;
|
this.loadMoreError = false;
|
||||||
|
|
||||||
this.resultsSource.setQuery('');
|
this.resultsSource.setQuery('');
|
||||||
this.resultsSource.reset();
|
this.resultsSource.reset();
|
||||||
|
@ -172,7 +172,7 @@ export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewI
|
||||||
try {
|
try {
|
||||||
await this.resultsSource?.load();
|
await this.resultsSource?.load();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.loadMoreError = CoreDomUtils.getErrorMessage(error);
|
this.loadMoreError = true;
|
||||||
} finally {
|
} finally {
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,11 @@ export class CoreErrorAccordionService {
|
||||||
* Render an instance of the component into an HTML string.
|
* Render an instance of the component into an HTML string.
|
||||||
*
|
*
|
||||||
* @param element Root element.
|
* @param element Root element.
|
||||||
* @param errorCode Error code.
|
|
||||||
* @param errorDetails Error details.
|
* @param errorDetails Error details.
|
||||||
|
* @param errorCode Error code.
|
||||||
*/
|
*/
|
||||||
async render(element: Element, errorCode: string, errorDetails: string): Promise<void> {
|
async render(element: Element, errorDetails: string, errorCode?: string): Promise<void> {
|
||||||
const html = this.html(errorCode, errorDetails);
|
const html = this.html(errorDetails, errorCode);
|
||||||
|
|
||||||
element.innerHTML = html;
|
element.innerHTML = html;
|
||||||
|
|
||||||
|
@ -56,15 +56,15 @@ export class CoreErrorAccordionService {
|
||||||
* @param errorDetails Error details.
|
* @param errorDetails Error details.
|
||||||
* @returns HTML.
|
* @returns HTML.
|
||||||
*/
|
*/
|
||||||
private html(errorCode: string, errorDetails: string): string {
|
private html(errorDetails: string, errorCode?: string): string {
|
||||||
const contentId = CoreForms.uniqueId('error-accordion-content');
|
const contentId = CoreForms.uniqueId('error-accordion-content');
|
||||||
const errorCodeLabel = Translate.instant('core.errorcode', { errorCode });
|
const errorCodeLabel = errorCode ? Translate.instant('core.errorcode', { errorCode }) : undefined;
|
||||||
const hideDetailsLabel = Translate.instant('core.errordetailshide');
|
const hideDetailsLabel = Translate.instant('core.errordetailshide');
|
||||||
const showDetailsLabel = Translate.instant('core.errordetailsshow');
|
const showDetailsLabel = Translate.instant('core.errordetailsshow');
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="core-error-accordion">
|
<div class="core-error-accordion">
|
||||||
<h3 class="core-error-accordion--code">${errorCodeLabel}</h3>
|
${errorCodeLabel ? `<h3 class="core-error-accordion--code">${errorCodeLabel}</h3>` : ''}
|
||||||
<div id="${contentId}" class="core-error-accordion--details" role="region" aria-hidden="true">
|
<div id="${contentId}" class="core-error-accordion--details" role="region" aria-hidden="true">
|
||||||
<p>${errorDetails}</p>
|
<p>${errorDetails}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,10 +13,11 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreAnyError, CoreError } from '@classes/errors/error';
|
import { CoreAnyError, CoreError, CoreErrorDebug } from '@classes/errors/error';
|
||||||
import { makeSingleton, Translate } from '@singletons';
|
import { makeSingleton, Translate } from '@singletons';
|
||||||
import { AlertButton } from '@ionic/angular';
|
import { AlertButton } from '@ionic/angular';
|
||||||
import { CoreWSError } from '@classes/errors/wserror';
|
import { CoreWSError } from '@classes/errors/wserror';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provider to provide some helper functions regarding files and packages.
|
* Provider to provide some helper functions regarding files and packages.
|
||||||
|
@ -130,6 +131,39 @@ export class CoreErrorHelperService {
|
||||||
return builtMessage;
|
return builtMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the debug info from an error object.
|
||||||
|
*
|
||||||
|
* @param error Error.
|
||||||
|
* @returns Error debug info, undefined if not found.
|
||||||
|
*/
|
||||||
|
getDebugInfoFromError(error?: CoreAnyError): CoreErrorDebug | undefined {
|
||||||
|
if (!error || typeof error === 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('debug' in error) {
|
||||||
|
return error.debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape the HTML of debug info so it is displayed as it is in the view.
|
||||||
|
const debugMessages: string[] = [];
|
||||||
|
if ('debuginfo' in error && error.debuginfo) {
|
||||||
|
debugMessages.push(CoreText.escapeHTML(error.debuginfo, false));
|
||||||
|
}
|
||||||
|
if ('backtrace' in error && error.backtrace) {
|
||||||
|
debugMessages.push(CoreText.replaceNewLines(
|
||||||
|
CoreText.escapeHTML(error.backtrace, false),
|
||||||
|
'<br>',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
const debugMessage = debugMessages.join('<br><br>');
|
||||||
|
if (debugMessage) {
|
||||||
|
return { details: debugMessage };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the error message from an error object.
|
* Get the error message from an error object.
|
||||||
*
|
*
|
||||||
|
|
|
@ -27,7 +27,7 @@ import {
|
||||||
CoreSiteConfig,
|
CoreSiteConfig,
|
||||||
} from '@classes/sites/site';
|
} from '@classes/sites/site';
|
||||||
import { SQLiteDB, SQLiteDBRecordValues, SQLiteDBTableSchema } from '@classes/sqlitedb';
|
import { SQLiteDB, SQLiteDBRecordValues, SQLiteDBTableSchema } from '@classes/sqlitedb';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError, CoreErrorDebug } from '@classes/errors/error';
|
||||||
import { CoreLoginError, CoreLoginErrorOptions } from '@classes/errors/loginerror';
|
import { CoreLoginError, CoreLoginErrorOptions } from '@classes/errors/loginerror';
|
||||||
import { makeSingleton, Translate, Http } from '@singletons';
|
import { makeSingleton, Translate, Http } from '@singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
@ -64,7 +64,6 @@ import { CoreSiteInfo, CoreSiteInfoResponse, CoreSitePublicConfigResponse } from
|
||||||
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
|
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { CoreHTMLClasses } from '@singletons/html-classes';
|
import { CoreHTMLClasses } from '@singletons/html-classes';
|
||||||
import { CoreSiteErrorDebug } from '@classes/errors/siteerror';
|
|
||||||
import { CoreErrorHelper } from './error-helper';
|
import { CoreErrorHelper } from './error-helper';
|
||||||
import { CoreQueueRunner } from '@classes/queue-runner';
|
import { CoreQueueRunner } from '@classes/queue-runner';
|
||||||
import { CoreAppDB } from './app-db';
|
import { CoreAppDB } from './app-db';
|
||||||
|
@ -287,14 +286,18 @@ export class CoreSitesProvider {
|
||||||
*
|
*
|
||||||
* @param siteUrl URL of the site to check.
|
* @param siteUrl URL of the site to check.
|
||||||
* @param protocol Protocol to use first.
|
* @param protocol Protocol to use first.
|
||||||
|
* @param origin Origin of this check site call.
|
||||||
* @returns A promise resolved when the site is checked.
|
* @returns A promise resolved when the site is checked.
|
||||||
*/
|
*/
|
||||||
async checkSite(siteUrl: string, protocol: string = 'https://'): Promise<CoreSiteCheckResponse> {
|
async checkSite(siteUrl: string, protocol: string = 'https://', origin = 'unknown'): Promise<CoreSiteCheckResponse> {
|
||||||
// The formatURL function adds the protocol if is missing.
|
// The formatURL function adds the protocol if is missing.
|
||||||
siteUrl = CoreUrl.formatURL(siteUrl);
|
siteUrl = CoreUrl.formatURL(siteUrl);
|
||||||
|
|
||||||
if (!CoreUrl.isHttpURL(siteUrl)) {
|
if (!CoreUrl.isHttpURL(siteUrl)) {
|
||||||
throw new CoreError(Translate.instant('core.login.invalidsite'));
|
throw new CoreError(Translate.instant('core.login.invalidsite'), {
|
||||||
|
code: 'invalidprotocol',
|
||||||
|
details: `URL contains an invalid protocol when checking site.<br><br>Origin: ${origin}.<br><br>URL: ${siteUrl}.`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CoreNetwork.isOnline()) {
|
if (!CoreNetwork.isOnline()) {
|
||||||
|
@ -459,7 +462,7 @@ export class CoreSitesProvider {
|
||||||
critical: true,
|
critical: true,
|
||||||
title: Translate.instant('core.cannotconnect'),
|
title: Translate.instant('core.cannotconnect'),
|
||||||
message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }),
|
message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }),
|
||||||
supportConfig: error.supportConfig,
|
supportConfig: 'supportConfig' in error ? error.supportConfig : undefined,
|
||||||
debug: error.debug,
|
debug: error.debug,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -688,7 +691,7 @@ export class CoreSitesProvider {
|
||||||
* @returns A promise rejected with the error info.
|
* @returns A promise rejected with the error info.
|
||||||
*/
|
*/
|
||||||
protected async treatInvalidAppVersion(result: number, siteId?: string): Promise<never> {
|
protected async treatInvalidAppVersion(result: number, siteId?: string): Promise<never> {
|
||||||
let debug: CoreSiteErrorDebug | undefined;
|
let debug: CoreErrorDebug | undefined;
|
||||||
let errorKey: string | undefined;
|
let errorKey: string | undefined;
|
||||||
let translateParams = {};
|
let translateParams = {};
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,22 @@ export class CoreCustomURLSchemesProvider {
|
||||||
this.logger = CoreLogger.getInstance('CoreCustomURLSchemesProvider');
|
this.logger = CoreLogger.getInstance('CoreCustomURLSchemesProvider');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a CoreCustomURLSchemesHandleError to be used when treating a URL that doesn't have a valid scheme.
|
||||||
|
*
|
||||||
|
* @param url URL that caused the error.
|
||||||
|
* @param data Data obtained from the URL (if any).
|
||||||
|
* @returns Error.
|
||||||
|
*/
|
||||||
|
protected createInvalidSchemeError(url: string, data?: CoreCustomURLSchemesParams): CoreCustomURLSchemesHandleError {
|
||||||
|
const defaultError = new CoreError(Translate.instant('core.login.invalidsite'), {
|
||||||
|
code: 'invalidurlscheme',
|
||||||
|
details: `Error when treating a URL scheme, it seems the URL is not valid.<br><br>URL: ${url}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new CoreCustomURLSchemesHandleError(defaultError, data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given some data of a custom URL with a token, create a site if it needs to be created.
|
* Given some data of a custom URL with a token, create a site if it needs to be created.
|
||||||
*
|
*
|
||||||
|
@ -62,7 +78,7 @@ export class CoreCustomURLSchemesProvider {
|
||||||
|
|
||||||
if (!data.siteUrl.match(/^https?:\/\//)) {
|
if (!data.siteUrl.match(/^https?:\/\//)) {
|
||||||
// URL doesn't have a protocol and it's required to be able to create the site. Check which one to use.
|
// URL doesn't have a protocol and it's required to be able to create the site. Check which one to use.
|
||||||
const result = await CoreSites.checkSite(data.siteUrl);
|
const result = await CoreSites.checkSite(data.siteUrl, undefined, 'URL scheme create site');
|
||||||
|
|
||||||
data.siteUrl = result.siteUrl;
|
data.siteUrl = result.siteUrl;
|
||||||
|
|
||||||
|
@ -90,7 +106,13 @@ export class CoreCustomURLSchemesProvider {
|
||||||
*/
|
*/
|
||||||
async handleCustomURL(url: string): Promise<void> {
|
async handleCustomURL(url: string): Promise<void> {
|
||||||
if (!this.isCustomURL(url)) {
|
if (!this.isCustomURL(url)) {
|
||||||
throw new CoreCustomURLSchemesHandleError(null);
|
throw this.createInvalidSchemeError(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there is nothing valid after the URL scheme.
|
||||||
|
const urlWithoutScheme = this.removeCustomURLScheme(url).trim();
|
||||||
|
if (!urlWithoutScheme || urlWithoutScheme.match(/^\/?(#.*)?\/?$/)) {
|
||||||
|
throw this.createInvalidSchemeError(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First check that this URL hasn't been treated a few seconds ago. The function that handles custom URL schemes already
|
/* First check that this URL hasn't been treated a few seconds ago. The function that handles custom URL schemes already
|
||||||
|
@ -202,7 +224,7 @@ export class CoreCustomURLSchemesProvider {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Site not stored. Try to add the site.
|
// Site not stored. Try to add the site.
|
||||||
const result = await CoreSites.checkSite(data.siteUrl);
|
const result = await CoreSites.checkSite(data.siteUrl, undefined, `URL scheme redirect: ${url}`);
|
||||||
|
|
||||||
// Site exists. We'll allow to add it.
|
// Site exists. We'll allow to add it.
|
||||||
modal.dismiss(); // Dismiss modal so it doesn't collide with confirms.
|
modal.dismiss(); // Dismiss modal so it doesn't collide with confirms.
|
||||||
|
@ -211,7 +233,12 @@ export class CoreCustomURLSchemesProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (!error || !CoreErrorHelper.getErrorMessageFromError(error)) {
|
||||||
|
// Use a default error.
|
||||||
|
this.createInvalidSchemeError(url, data);
|
||||||
|
} else {
|
||||||
throw new CoreCustomURLSchemesHandleError(error, data);
|
throw new CoreCustomURLSchemesHandleError(error, data);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
modal.dismiss();
|
modal.dismiss();
|
||||||
|
|
||||||
|
@ -230,7 +257,7 @@ export class CoreCustomURLSchemesProvider {
|
||||||
*/
|
*/
|
||||||
protected async getCustomURLData(url: string): Promise<CoreCustomURLSchemesParams> {
|
protected async getCustomURLData(url: string): Promise<CoreCustomURLSchemesParams> {
|
||||||
if (!this.isCustomURL(url)) {
|
if (!this.isCustomURL(url)) {
|
||||||
throw new CoreCustomURLSchemesHandleError(null);
|
throw this.createInvalidSchemeError(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// App opened using custom URL scheme.
|
// App opened using custom URL scheme.
|
||||||
|
@ -283,7 +310,7 @@ export class CoreCustomURLSchemesProvider {
|
||||||
*/
|
*/
|
||||||
protected async getCustomURLLinkData(url: string): Promise<CoreCustomURLSchemesParams> {
|
protected async getCustomURLLinkData(url: string): Promise<CoreCustomURLSchemesParams> {
|
||||||
if (!this.isCustomURLLink(url)) {
|
if (!this.isCustomURLLink(url)) {
|
||||||
throw new CoreCustomURLSchemesHandleError(null);
|
throw this.createInvalidSchemeError(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// App opened using custom URL scheme.
|
// App opened using custom URL scheme.
|
||||||
|
@ -345,7 +372,7 @@ export class CoreCustomURLSchemesProvider {
|
||||||
*/
|
*/
|
||||||
protected async getCustomURLTokenData(url: string): Promise<CoreCustomURLSchemesParams> {
|
protected async getCustomURLTokenData(url: string): Promise<CoreCustomURLSchemesParams> {
|
||||||
if (!this.isCustomURLToken(url)) {
|
if (!this.isCustomURLToken(url)) {
|
||||||
throw new CoreCustomURLSchemesHandleError(null);
|
throw this.createInvalidSchemeError(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CoreSSO.isSSOAuthenticationOngoing()) {
|
if (CoreSSO.isSSOAuthenticationOngoing()) {
|
||||||
|
@ -358,6 +385,7 @@ export class CoreCustomURLSchemesProvider {
|
||||||
this.logger.debug('App launched by URL with an SSO');
|
this.logger.debug('App launched by URL with an SSO');
|
||||||
|
|
||||||
// Delete the sso scheme from the URL.
|
// Delete the sso scheme from the URL.
|
||||||
|
const originalUrl = url;
|
||||||
url = this.removeCustomURLTokenScheme(url);
|
url = this.removeCustomURLTokenScheme(url);
|
||||||
|
|
||||||
// Some platforms like Windows add a slash at the end. Remove it.
|
// Some platforms like Windows add a slash at the end. Remove it.
|
||||||
|
@ -371,7 +399,11 @@ export class CoreCustomURLSchemesProvider {
|
||||||
// Error decoding the parameter.
|
// Error decoding the parameter.
|
||||||
this.logger.error('Error decoding parameter received for login SSO');
|
this.logger.error('Error decoding parameter received for login SSO');
|
||||||
|
|
||||||
throw new CoreCustomURLSchemesHandleError(null);
|
throw new CoreCustomURLSchemesHandleError(new CoreError(Translate.instant('core.login.invalidsite'), {
|
||||||
|
code: 'errordecodingparameter',
|
||||||
|
details: `Error when trying to decode base 64 string.<br><br>URL: ${originalUrl}<br><br>Text to decode: ${url}` +
|
||||||
|
`<br><br>Error: ${CoreErrorHelper.getErrorMessageFromError(err)}`,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: CoreCustomURLSchemesParams = await CoreLoginHelper.validateBrowserSSOLogin(url);
|
const data: CoreCustomURLSchemesParams = await CoreLoginHelper.validateBrowserSSOLogin(url);
|
||||||
|
@ -491,14 +523,17 @@ export class CoreCustomURLSchemesProvider {
|
||||||
* @param error Error data.
|
* @param error Error data.
|
||||||
*/
|
*/
|
||||||
treatHandleCustomURLError(error: CoreCustomURLSchemesHandleError): void {
|
treatHandleCustomURLError(error: CoreCustomURLSchemesHandleError): void {
|
||||||
if (error.error == 'Duplicated') {
|
if (error.error === 'Duplicated') {
|
||||||
// Duplicated request
|
// Duplicated request
|
||||||
} else if (CoreWSError.isWebServiceError(error.error) && error.data && error.data.isSSOToken) {
|
} else if (CoreWSError.isWebServiceError(error.error) && error.data && error.data.isSSOToken) {
|
||||||
// An error occurred, display the error and logout the user.
|
// An error occurred, display the error and logout the user.
|
||||||
CoreLoginHelper.treatUserTokenError(error.data.siteUrl, <CoreWSError> error.error);
|
CoreLoginHelper.treatUserTokenError(error.data.siteUrl, <CoreWSError> error.error);
|
||||||
CoreSites.logout();
|
CoreSites.logout();
|
||||||
} else {
|
} else {
|
||||||
CoreDomUtils.showErrorModalDefault(error.error, Translate.instant('core.login.invalidsite'));
|
CoreDomUtils.showErrorModal(error.error ?? new CoreError(Translate.instant('core.login.invalidsite'), {
|
||||||
|
code: 'unknownerror',
|
||||||
|
details: 'Unknown error when treating a URL scheme.',
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -449,17 +449,6 @@ export class CoreDomUtilsProvider {
|
||||||
|
|
||||||
if (typeof error === 'object') {
|
if (typeof error === 'object') {
|
||||||
if (this.debugDisplay) {
|
if (this.debugDisplay) {
|
||||||
// Get the debug info. Escape the HTML so it is displayed as it is in the view.
|
|
||||||
if ('debuginfo' in error && error.debuginfo) {
|
|
||||||
extraInfo = '<br><br>' + CoreText.escapeHTML(error.debuginfo, false);
|
|
||||||
}
|
|
||||||
if ('backtrace' in error && error.backtrace) {
|
|
||||||
extraInfo += '<br><br>' + CoreText.replaceNewLines(
|
|
||||||
CoreText.escapeHTML(error.backtrace, false),
|
|
||||||
'<br>',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
@ -1061,36 +1050,35 @@ export class CoreDomUtilsProvider {
|
||||||
|
|
||||||
if (typeof error !== 'string' && 'buttons' in error && typeof error.buttons !== 'undefined') {
|
if (typeof error !== 'string' && 'buttons' in error && typeof error.buttons !== 'undefined') {
|
||||||
alertOptions.buttons = error.buttons;
|
alertOptions.buttons = error.buttons;
|
||||||
} else if (error instanceof CoreSiteError) {
|
} else {
|
||||||
if (error.debug) {
|
alertOptions.buttons = [Translate.instant('core.ok')];
|
||||||
alertOptions.message = `<p>${alertOptions.message}</p><div class="core-error-accordion-container"></div>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const supportConfig = error.supportConfig;
|
// For site errors, always show debug info.
|
||||||
|
const showDebugInfo = this.debugDisplay || error instanceof CoreSiteError;
|
||||||
|
const debugInfo = showDebugInfo && CoreErrorHelper.getDebugInfoFromError(error);
|
||||||
|
if (debugInfo) {
|
||||||
|
alertOptions.message = `<p>${message}</p><div class="core-error-accordion-container"></div>`;
|
||||||
|
}
|
||||||
|
|
||||||
alertOptions.buttons = [Translate.instant('core.ok')];
|
if (error instanceof CoreSiteError && error.supportConfig?.canContactSupport()) {
|
||||||
|
|
||||||
if (supportConfig?.canContactSupport()) {
|
|
||||||
alertOptions.buttons.push({
|
alertOptions.buttons.push({
|
||||||
text: Translate.instant('core.contactsupport'),
|
text: Translate.instant('core.contactsupport'),
|
||||||
handler: () => CoreUserSupport.contact({
|
handler: () => CoreUserSupport.contact({
|
||||||
supportConfig,
|
supportConfig: error.supportConfig,
|
||||||
subject: alertOptions.header,
|
subject: alertOptions.header,
|
||||||
message: `${error.debug?.code}\n\n${error.debug?.details}`,
|
message: `${error.debug?.code}\n\n${error.debug?.details}`,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
alertOptions.buttons = [Translate.instant('core.ok')];
|
|
||||||
}
|
|
||||||
|
|
||||||
const alertElement = await this.showAlertWithOptions(alertOptions, autocloseTime);
|
const alertElement = await this.showAlertWithOptions(alertOptions, autocloseTime);
|
||||||
|
|
||||||
if (error instanceof CoreSiteError && error.debug) {
|
if (debugInfo) {
|
||||||
const containerElement = alertElement.querySelector('.core-error-accordion-container');
|
const containerElement = alertElement.querySelector('.core-error-accordion-container');
|
||||||
|
|
||||||
if (containerElement) {
|
if (containerElement) {
|
||||||
await CoreErrorAccordion.render(containerElement, error.debug.code, error.debug.details);
|
await CoreErrorAccordion.render(containerElement, debugInfo.details, debugInfo.code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue