forked from EVOgeek/Vmeda.Online
		
	MOBILE-4059 core: Update cannot connect messages
This commit is contained in:
		
							parent
							
								
									c4952133f1
								
							
						
					
					
						commit
						e1035e9a4b
					
				| @ -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", | ||||
|  | ||||
| @ -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()!; | ||||
|  | ||||
| @ -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.
 | ||||
| }; | ||||
|  | ||||
| @ -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.
 | ||||
| 
 | ||||
|  | ||||
| @ -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.
 | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
							
								
								
									
										59
									
								
								src/core/services/tests/utils/dom.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/core/services/tests/utils/dom.test.ts
									
									
									
									
									
										Normal 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')], | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
| }); | ||||
| @ -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')]; | ||||
|         } | ||||
|  | ||||
| @ -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'), | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|         }, | ||||
|     }); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user