MOBILE-4059 core: Update cannot connect messages

main
Noel De Martin 2022-11-03 13:27:55 +01:00
parent c4952133f1
commit e1035e9a4b
15 changed files with 205 additions and 126 deletions

View File

@ -1471,9 +1471,6 @@
"core.calculating": "local_moodlemobileapp",
"core.cancel": "moodle",
"core.cannotconnect": "local_moodlemobileapp",
"core.cannotconnecttrouble": "local_moodlemobileapp",
"core.cannotconnecttroublewithoutsupport": "local_moodlemobileapp",
"core.cannotconnectverify": "local_moodlemobileapp",
"core.cannotdownloadfiles": "local_moodlemobileapp",
"core.cannotinstallapk": "local_moodlemobileapp",
"core.cannotlogoutpageblocks": "local_moodlemobileapp",
@ -1520,6 +1517,7 @@
"core.confirmleaveunknownchanges": "local_moodlemobileapp",
"core.confirmloss": "local_moodlemobileapp",
"core.confirmopeninbrowser": "local_moodlemobileapp",
"core.connectionlost": "local_moodlemobileapp",
"core.considereddigitalminor": "moodle",
"core.contactsupport": "local_moodlemobileapp",
"core.content": "moodle",
@ -2273,6 +2271,9 @@
"core.sitehome.sitehome": "moodle",
"core.sitehome.sitenews": "moodle",
"core.sitemaintenance": "admin",
"core.sitenotfound": "local_moodlemobileapp",
"core.sitenotfoundhelp": "local_moodlemobileapp",
"core.siteunavailablehelp": "local_moodlemobileapp",
"core.size": "moodle",
"core.sizeb": "moodle",
"core.sizegb": "moodle",

View File

@ -15,6 +15,7 @@
import { Injectable } from '@angular/core';
import { CoreError } from '@classes/errors/error';
import { CoreSite } from '@classes/site';
import { CoreCourseActivitySyncBaseProvider } from '@features/course/classes/activity-sync';
import { CoreCourse, CoreCourseModuleBasicInfo } from '@features/course/services/course';
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
@ -313,7 +314,7 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
if (!CoreNetwork.isOnline()) {
// Cannot sync in offline.
throw new CoreError(Translate.instant('core.cannotconnect'));
throw new CoreError(Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }));
}
const offlineAttempt = offlineAttempts.pop()!;

View File

@ -19,12 +19,14 @@ import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror';
*/
export class CoreLoginError extends CoreSiteError {
title?: string;
critical?: boolean;
loggedOut?: boolean;
constructor(options: CoreLoginErrorOptions) {
super(options);
this.title = options.title;
this.critical = options.critical;
this.loggedOut = options.loggedOut;
}
@ -32,6 +34,7 @@ export class CoreLoginError extends CoreSiteError {
}
export type CoreLoginErrorOptions = CoreSiteErrorOptions & {
title?: string; // Error title.
critical?: boolean; // Whether the error is important enough to abort the operation.
loggedOut?: boolean; // Whether site has been marked as logged out.
};

View File

@ -25,7 +25,7 @@ export class CoreSiteError extends CoreError {
supportConfig?: CoreUserSupportConfig;
constructor(options: CoreSiteErrorOptions) {
super(getErrorMessage(options));
super(options.message);
this.errorcode = options.errorcode;
this.errorDetails = options.errorDetails;
@ -34,23 +34,8 @@ export class CoreSiteError extends CoreError {
}
/**
* Get message to use in the error.
*
* @param options Error options.
* @returns Error message.
*/
function getErrorMessage(options: CoreSiteErrorOptions): string {
if ('supportConfig' in options && !options.supportConfig?.canContactSupport()) {
return options.fallbackMessage ?? options.message;
}
return options.message;
}
export type CoreSiteErrorOptions = {
message: string;
fallbackMessage?: string; // Message to use when contacting support is not possible but warranted.
errorcode?: string; // Technical error code useful for technical assistance.
errorDetails?: string; // Technical error details useful for technical assistance.

View File

@ -810,9 +810,7 @@ export class CoreSite {
): Promise<T> {
if (preSets.forceOffline) {
// Don't call the WS, just fail.
throw new CoreError(
Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
);
throw new CoreError(Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }));
}
try {
@ -1134,8 +1132,7 @@ export class CoreSite {
if (!data || !data.responses) {
throw new CoreSiteError({
supportConfig: new CoreUserAuthenticatedSupportConfig(this),
message: Translate.instant('core.cannotconnecttrouble'),
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
message: Translate.instant('core.siteunavailablehelp', { site: this.siteUrl }),
errorcode: 'invalidresponse',
errorDetails: Translate.instant('core.errorinvalidresponse', { method: 'tool_mobile_call_external_functions' }),
});
@ -1726,9 +1723,7 @@ export class CoreSite {
.catch(async () => {
if (cachePreSets.forceOffline) {
// Don't call the WS, just fail.
throw new CoreError(
Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
);
throw new CoreError(Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }));
}
// Call the WS.

View File

@ -27,7 +27,6 @@ import {
CoreLoginSiteFinderSettings,
CoreLoginSiteSelectorListMethod,
} from '@features/login/services/login-helper';
import { CoreSite } from '@classes/site';
import { CoreError } from '@classes/errors/error';
import { CoreConstants } from '@/core/constants';
import { Translate } from '@singletons';
@ -45,6 +44,8 @@ import { CoreUserSupport } from '@features/user/services/support';
import { CoreErrorInfoComponent } from '@components/error-info/error-info';
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
import { CoreLoginError } from '@classes/errors/loginerror';
import { CoreSite } from '@classes/site';
/**
* Site (url) chooser when adding a new site.
@ -389,6 +390,7 @@ export class CoreLoginSitePage implements OnInit {
let errorMessage = CoreDomUtils.getErrorMessage(error);
let siteExists = false;
let supportConfig: CoreUserSupportConfig | undefined = undefined;
let errorTitle: string | undefined;
let errorDetails: string | undefined;
let errorCode: string | undefined;
@ -399,32 +401,21 @@ export class CoreLoginSitePage implements OnInit {
siteExists = supportConfig instanceof CoreUserGuestSupportConfig;
}
if (
!siteExists && (
errorMessage === Translate.instant('core.cannotconnecttrouble') ||
errorMessage === Translate.instant('core.cannotconnecttroublewithoutsupport')
)
) {
const found = this.sites.find((site) => site.url == url);
if (!found) {
errorMessage += ' ' + Translate.instant('core.cannotconnectverify');
}
}
errorMessage = '<p>' + errorMessage + '</p>';
if (!siteExists && url) {
const fullUrl = CoreUrlUtils.isAbsoluteURL(url) ? url : 'https://' + url;
errorMessage += '<p padding><a href="' + fullUrl + '" core-link>' + url + '</a></p>';
if (error instanceof CoreLoginError) {
errorTitle = error.title;
}
if (errorDetails) {
errorMessage += '<div class="core-error-info-container"></div>';
errorMessage = `<p>${errorMessage}</p><div class="core-error-info-container"></div>`;
}
const alertSupportConfig = supportConfig;
const buttons: AlertButton[] = [
alertSupportConfig
const buttons = [
{
text: Translate.instant('core.tryagain'),
role: 'cancel',
},
alertSupportConfig?.canContactSupport()
? {
text: Translate.instant('core.contactsupport'),
handler: () => CoreUserSupport.contact({
@ -433,22 +424,26 @@ export class CoreLoginSitePage implements OnInit {
message: `Error: ${errorCode}\n\n${errorDetails}`,
}),
}
: {
text: Translate.instant('core.needhelp'),
cssClass: 'core-login-need-help',
handler: () => this.showHelp(),
},
{
text: Translate.instant('core.tryagain'),
role: 'cancel',
},
];
: (
!siteExists
? {
text: Translate.instant('core.needhelp'),
cssClass: 'core-login-need-help',
handler: () => this.showHelp(),
}
: null
),
].filter(button => !!button);
// @TODO: Remove CoreSite.MINIMUM_MOODLE_VERSION, not used on translations since 3.9.0.
const alertElement = await CoreDomUtils.showAlertWithOptions({
header: Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
message: errorMessage,
buttons,
header: errorTitle ?? (
siteExists
? Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION })
: Translate.instant('core.sitenotfound')
),
message: errorMessage ?? Translate.instant('core.sitenotfoundhelp'),
buttons: buttons as AlertButton[],
});
if (errorDetails) {

View File

@ -39,14 +39,10 @@ Feature: Test basic usage of login in app
But I should not find "Log in" in the app
Scenario: Add a non existing account
When I enter the app
And I log in as "student1"
When I log out in the app
And I press "Add" in the app
And I set the field "Your site" to "Wrong Site Address" in the app
And I press enter in the app
Then I should find "Cannot connect" in the app
And I should find "Wrong Site Address" in the app
When I launch the app
And I set the field "Your site" to "wrongsiteaddress" in the app
And I press "Connect to your site" in the app
Then I should find "Site not found" in the app
Scenario: Add a non existing account from accounts switcher
When I enter the app
@ -55,10 +51,9 @@ Feature: Test basic usage of login in app
And I press "Switch account" in the app
And I press "Add" in the app
And I wait the app to restart
And I set the field "Your site" to "Wrong Site Address" in the app
And I press enter in the app
Then I should find "Cannot connect" in the app
And I should find "Wrong Site Address" in the app
And I set the field "Your site" to "wrongsiteaddress" in the app
And I press "Connect to your site" in the app
Then I should find "Site not found" in the app
Scenario: Log out from the app
Given I entered the app as "student1"

View File

@ -53,10 +53,7 @@ export default function(): void {
supportConfig: CoreSites.getCurrentSite()
? CoreUserAuthenticatedSupportConfig.forCurrentSite()
: new CoreUserNullSupportConfig(),
message: Translate.instant('core.cannotconnecttrouble'),
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
errorcode: 'invalidurlscheme',
errorDetails: Translate.instant('core.errorurlschemeinvalidscheme', { $a: urlScheme }),
message: Translate.instant('core.errorurlschemeinvalidscheme', { $a: urlScheme }),
}));
return;

View File

@ -14,10 +14,7 @@
"browser": "Browser",
"calculating": "Calculating",
"cancel": "Cancel",
"cannotconnect": "Cannot connect",
"cannotconnecttrouble": "We're having trouble connecting to your site.",
"cannotconnecttroublewithoutsupport": "We're having trouble connecting to your site, please contact your institution.",
"cannotconnectverify": "<strong>Please check the address is correct.</strong>",
"cannotconnect": "Can't connect to site",
"cannotdownloadfiles": "This institution has disabled downloading files.",
"cannotinstallapk": "For security reasons, you can't install unknown apps on your device from this app. Please open the file using a browser.",
"cannotlogoutpageblocks": "Please save or discard your changes before continuing.",
@ -54,6 +51,7 @@
"confirmleaveunknownchanges": "Are you sure you want to leave this page? If you have unsaved changes they will be lost.",
"confirmloss": "Are you sure? All changes will be lost.",
"confirmopeninbrowser": "Do you want to open it in a web browser?",
"connectionlost": "Connection to site lost",
"considereddigitalminor": "You are too young to create an account on this site.",
"contactsupport": "Contact support",
"content": "Content",
@ -282,6 +280,9 @@
"showmore": "Show more...",
"site": "Site",
"sitemaintenance": "The site is undergoing maintenance and is currently not available",
"sitenotfound": "Site not found",
"sitenotfoundhelp": "We can't find the site you entered. Please check for typos or try again later. If you keep seeing this message, contact your school or learning provider.",
"siteunavailablehelp": "The site \"{{site}}\" is not available right now. Please try again later or contact your school or learning provider.",
"size": "Size",
"sizeb": "bytes",
"sizegb": "GB",

View File

@ -55,6 +55,7 @@ import { lazyMap, LazyMap } from '../utils/lazy-map';
import { asyncInstance, AsyncInstance } from '../utils/async-instance';
import { CoreText } from '@singletons/text';
import { CorePromisedValue } from '@classes/promised-value';
import { CoreSite } from '@classes/site';
/*
* Factory for handling downloading files and retrieve downloaded files.
@ -509,7 +510,7 @@ export class CoreFilepoolProvider {
} else {
if (!CoreNetwork.isOnline()) {
// Cannot check size in offline, stop.
throw new CoreError(Translate.instant('core.cannotconnect'));
throw new CoreError(Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }));
}
size = await CoreWS.getRemoteFileSize(fileUrl);

View File

@ -246,7 +246,7 @@ export class CoreSitesProvider {
} else if (CoreTextUtils.getErrorMessageFromError(secondError)) {
throw secondError;
} else {
throw new CoreError(Translate.instant('core.cannotconnecttrouble'));
throw new CoreError(Translate.instant('core.sitenotfoundhelp'));
}
}
}
@ -297,14 +297,14 @@ export class CoreSitesProvider {
// Check that the user can authenticate.
if (!config.enablewebservices) {
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(config.httpswwwroot || config.wwwroot, {
supportConfig: new CoreUserGuestSupportConfig(config),
errorcode: 'webservicesnotenabled',
errorDetails: Translate.instant('core.login.webservicesnotenabled'),
critical: true,
});
} else if (!config.enablemobilewebservice) {
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(config.httpswwwroot || config.wwwroot, {
supportConfig: new CoreUserGuestSupportConfig(config),
errorcode: 'mobileservicesnotenabled',
errorDetails: Translate.instant('core.login.mobileservicesnotenabled'),
@ -333,11 +333,12 @@ export class CoreSitesProvider {
* @param options Error options.
* @return Cannot connect error.
*/
protected createCannotConnectLoginError(options?: Partial<CoreLoginErrorOptions>): CoreLoginError {
protected createCannotConnectLoginError(siteUrl: string | null, options?: Partial<CoreLoginErrorOptions>): CoreLoginError {
return new CoreLoginError({
...options,
message: Translate.instant('core.cannotconnecttrouble'),
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
message: !this.isLoggedIn() && siteUrl === null
? Translate.instant('core.sitenotfoundhelp')
: Translate.instant('core.siteunavailablehelp', { site: siteUrl ?? this.currentSite?.siteUrl }),
});
}
@ -355,7 +356,10 @@ export class CoreSitesProvider {
if (error instanceof CoreAjaxError || !('errorcode' in error)) {
// The WS didn't return data, probably cannot connect.
return new CoreLoginError({
message: error.message || '',
title: Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }),
errorcode: 'publicconfigfailed',
errorDetails: error.message || '',
critical: false, // Allow fallback to http if siteUrl uses https.
});
}
@ -363,30 +367,27 @@ export class CoreSitesProvider {
// Service supported but an error happened. Return error.
const options: CoreLoginErrorOptions = {
critical: true,
message: error.message,
title: Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }),
errorcode: error.errorcode,
supportConfig: error.supportConfig,
errorDetails: error.errorDetails,
errorDetails: error.errorDetails ?? error.message,
};
if (error.errorcode === 'codingerror') {
// This could be caused by a redirect. Check if it's the case.
const redirect = await CoreUtils.checkRedirect(siteUrl);
options.message = Translate.instant('core.siteunavailablehelp', { site: siteUrl });
if (redirect) {
options.message = Translate.instant('core.cannotconnecttrouble');
options.fallbackMessage = Translate.instant('core.cannotconnecttroublewithoutsupport');
options.errorcode = 'sitehasredirect';
options.errorDetails = Translate.instant('core.login.sitehasredirect');
options.critical = false; // Keep checking fallback URLs.
} else {
// We can't be sure if there is a redirect or not. Display cannot connect error.
options.message = Translate.instant('core.cannotconnecttrouble');
}
} else if (error.errorcode === 'invalidrecord') {
// WebService not found, site not supported.
options.message = Translate.instant('core.cannotconnecttrouble');
options.fallbackMessage = Translate.instant('core.cannotconnecttroublewithoutsupport');
options.message = Translate.instant('core.siteunavailablehelp', { site: siteUrl });
options.errorcode = 'invalidmoodleversion';
options.errorDetails = Translate.instant('core.login.invalidmoodleversion', { $a: CoreSite.MINIMUM_MOODLE_VERSION });
} else if (error.errorcode === 'redirecterrordetected') {
@ -413,7 +414,7 @@ export class CoreSitesProvider {
data = await Http.post(siteUrl + '/login/token.php', { appsitecheck: 1 }).pipe(timeout(CoreWS.getRequestTimeout()))
.toPromise();
} catch (error) {
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(null, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
errorcode: 'sitecheckfailed',
errorDetails: CoreDomUtils.getErrorMessage(error) ?? undefined,
@ -422,7 +423,7 @@ export class CoreSitesProvider {
if (data === null) {
// Cannot connect.
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(null, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
errorcode: 'appsitecheckfailed',
errorDetails: 'A request to /login/token.php with appsitecheck=1 returned an empty response',
@ -430,7 +431,7 @@ export class CoreSitesProvider {
}
if (data.errorcode && (data.errorcode == 'enablewsdescription' || data.errorcode == 'requirecorrectaccess')) {
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(siteUrl, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
critical: data.errorcode == 'enablewsdescription',
errorcode: data.errorcode,
@ -439,7 +440,7 @@ export class CoreSitesProvider {
}
if (data.error && data.error == 'Web services must be enabled in Advanced features.') {
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(siteUrl, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
critical: true,
errorcode: 'enablewsdescription',
@ -483,11 +484,19 @@ export class CoreSitesProvider {
try {
data = await Http.post(loginUrl, params).pipe(timeout(CoreWS.getRequestTimeout())).toPromise();
} catch (error) {
throw new CoreError(Translate.instant('core.cannotconnecttrouble'));
throw new CoreError(
this.isLoggedIn()
? Translate.instant('core.siteunavailablehelp', { site: this.currentSite?.siteUrl })
: Translate.instant('core.sitenotfoundhelp'),
);
}
if (data === undefined) {
throw new CoreError(Translate.instant('core.cannotconnecttrouble'));
throw new CoreError(
this.isLoggedIn()
? Translate.instant('core.siteunavailablehelp', { site: this.currentSite?.siteUrl })
: Translate.instant('core.sitenotfoundhelp'),
);
} else {
if (data.token !== undefined) {
return { token: data.token, siteUrl, privateToken: data.privatetoken };
@ -503,7 +512,7 @@ export class CoreSitesProvider {
const redirect = await CoreUtils.checkRedirect(loginUrl);
if (redirect) {
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(siteUrl, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
errorcode: 'sitehasredirect',
errorDetails: Translate.instant('core.login.sitehasredirect'),
@ -511,7 +520,7 @@ export class CoreSitesProvider {
}
}
throw this.createCannotConnectLoginError({
throw this.createCannotConnectLoginError(siteUrl, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
errorcode: data.errorcode,
errorDetails: data.error,

View File

@ -0,0 +1,59 @@
// (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 { CoreDomUtilsProvider } from '@services/utils/dom';
import { AlertController, Translate } from '@singletons';
import { mock, mockSingleton, mockTranslate } from '@/testing/utils';
import { CoreSiteError } from '@classes/errors/siteerror';
import { CoreSites } from '@services/sites';
describe('CoreDomUtilsProvider', () => {
let domUtils: CoreDomUtilsProvider;
beforeEach(() => {
domUtils = new CoreDomUtilsProvider();
});
it('shows site unavailable errors', async () => {
// Arrange.
mockTranslate({
'core.siteunavailablehelp': 'The site "{{site}}" is not available right now.',
});
const message = Translate.instant('core.siteunavailablehelp', { site: 'https://campus.example.edu' });
const mockAlert = mock<HTMLIonAlertElement>({
present: () => Promise.resolve(),
onDidDismiss: async <T>() => new Promise<T>(() => {
// Never resolve.
}),
});
mockSingleton(AlertController, mock({ create: () => Promise.resolve(mockAlert) }));
mockSingleton(CoreSites, mock({ isLoggedIn: () => true }));
// Act.
await domUtils.showErrorModal(new CoreSiteError({ message }));
// Assert.
expect(mockAlert.present).toHaveBeenCalled();
expect(AlertController.create).toHaveBeenCalledWith({
message,
header: Translate.instant('core.connectionlost'),
buttons: [Translate.instant('core.ok')],
});
});
});

View File

@ -57,6 +57,7 @@ import { CoreNetwork } from '@services/network';
import { CoreSiteError } from '@classes/errors/siteerror';
import { CoreUserSupport } from '@features/user/services/support';
import { CoreErrorInfoComponent } from '@components/error-info/error-info';
import { CoreSite } from '@classes/site';
/*
* "Utils" service with helper functions for UI, DOM elements and HTML code.
@ -576,6 +577,20 @@ export class CoreDomUtilsProvider {
error instanceof CoreNetworkError;
}
/**
* Given a message, check if it's a site unavailable error.
*
* @param message Message text.
* @returns Whether the message is a site unavailable error.
*/
protected isSiteUnavailableError(message: string): boolean {
let siteUnavailableMessage = Translate.instant('core.siteunavailablehelp', { site: 'SITEURLPLACEHOLDER' });
siteUnavailableMessage = CoreTextUtils.escapeForRegex(siteUnavailableMessage);
siteUnavailableMessage = siteUnavailableMessage.replace('SITEURLPLACEHOLDER', '.*');
return new RegExp(siteUnavailableMessage).test(message);
}
/**
* Get the error message from an error, including debug data if needed.
*
@ -1345,14 +1360,20 @@ export class CoreDomUtilsProvider {
return null;
}
const alertOptions: AlertOptions = {
message: message,
};
const alertOptions: AlertOptions = { message };
if (this.isNetworkError(message, error)) {
alertOptions.cssClass = 'core-alert-network-error';
} else if (typeof error !== 'string' && 'title' in error) {
}
if (typeof error !== 'string' && 'title' in error && error.title) {
alertOptions.header = error.title || undefined;
} else if (message === Translate.instant('core.sitenotfoundhelp')) {
alertOptions.header = Translate.instant('core.sitenotfound');
} else if (this.isSiteUnavailableError(message)) {
alertOptions.header = CoreSites.isLoggedIn()
? Translate.instant('core.connectionlost')
: Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION });
} else {
alertOptions.header = Translate.instant('core.error');
}
@ -1360,13 +1381,14 @@ export class CoreDomUtilsProvider {
if (typeof error !== 'string' && 'buttons' in error && typeof error.buttons !== 'undefined') {
alertOptions.buttons = error.buttons;
} else if (error instanceof CoreSiteError) {
alertOptions.buttons = [];
if (error.errorDetails) {
alertOptions.message += '<div class="core-error-info-container"></div>';
alertOptions.message = `<p>${alertOptions.message}</p><div class="core-error-info-container"></div>`;
}
const supportConfig = error.supportConfig;
alertOptions.buttons = [Translate.instant('core.ok')];
if (supportConfig?.canContactSupport()) {
alertOptions.buttons.push({
text: Translate.instant('core.contactsupport'),
@ -1377,8 +1399,6 @@ export class CoreDomUtilsProvider {
}),
});
}
alertOptions.buttons.push(Translate.instant('core.ok'));
} else {
alertOptions.buttons = [Translate.instant('core.ok')];
}

View File

@ -41,6 +41,7 @@ import { CorePromisedValue } from '@classes/promised-value';
import { CorePlatform } from '@services/platform';
import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror';
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
import { CoreSites } from '@services/sites';
/**
* This service allows performing WS calls and download/upload files.
@ -469,10 +470,13 @@ export class CoreWSProvider {
// Check if error. Ajax layer should always return an object (if error) or an array (if success).
if (!data || typeof data != 'object') {
const message = CoreSites.isLoggedIn()
? Translate.instant('core.siteunavailablehelp', { site: CoreSites.getCurrentSite()?.siteUrl })
: Translate.instant('core.sitenotfoundhelp');
throw new CoreAjaxError({
message,
supportConfig: await CoreUserGuestSupportConfig.forSite(preSets.siteUrl),
message: Translate.instant('core.cannotconnecttrouble'),
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
errorcode: 'invalidresponse',
errorDetails: Translate.instant('core.serverconnection', {
details: Translate.instant('core.errorinvalidresponse', { method }),
@ -491,10 +495,13 @@ export class CoreWSProvider {
return data.data;
}, async (data: HttpErrorResponse) => {
const message = CoreSites.isLoggedIn()
? Translate.instant('core.siteunavailablehelp', { site: CoreSites.getCurrentSite()?.siteUrl })
: Translate.instant('core.sitenotfoundhelp');
const options: CoreSiteErrorOptions = {
message,
supportConfig: await CoreUserGuestSupportConfig.forSite(preSets.siteUrl),
message: Translate.instant('core.cannotconnecttrouble'),
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
};
switch (data.status) {
@ -988,7 +995,9 @@ export class CoreWSProvider {
*/
protected createHttpError(error: CoreTextErrorObject, status: number): CoreHttpError {
const message = CoreTextUtils.buildSeveralParagraphsMessage([
Translate.instant('core.cannotconnecttrouble'),
CoreSites.isLoggedIn()
? Translate.instant('core.siteunavailablehelp', { site: CoreSites.getCurrentSite()?.siteUrl })
: Translate.instant('core.sitenotfoundhelp'),
CoreTextUtils.getHTMLBodyContent(CoreTextUtils.getErrorMessageFromError(error) || ''),
]);
@ -1130,8 +1139,9 @@ export class CoreWSProvider {
return new CoreSiteError({
...options,
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
message: Translate.instant('core.cannotconnecttrouble'),
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
message: CoreSites.isLoggedIn()
? Translate.instant('core.siteunavailablehelp', { site: CoreSites.getCurrentSite()?.siteUrl })
: Translate.instant('core.sitenotfoundhelp'),
});
}

View File

@ -392,8 +392,15 @@ export function wait(time: number): Promise<void> {
*/
export function mockTranslate(translations: Record<string, string> = {}): void {
mockSingleton(Translate as CoreSingletonProxy<TranslateService>, {
instant: (key) => Array.isArray(key)
? key.map(k => translations[k] ?? k)
: translations[key] ?? key,
instant: (key, replacements) => {
const applyReplacements = (text: string): string => Object.entries(replacements ?? {}).reduce(
(text, [name, value]) => text.replace(`{{${name}}}`, value),
text,
);
return Array.isArray(key)
? key.map(k => applyReplacements(translations[k] ?? k))
: applyReplacements(translations[key] ?? key);
},
});
}