MOBILE-4059 core: Encapsulate support config
parent
b933c92f69
commit
c4952133f1
|
@ -13,8 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreSitePublicConfigResponse } from '@classes/site';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||
|
||||
/**
|
||||
* Error returned when performing operations regarding a site.
|
||||
|
@ -23,42 +22,14 @@ export class CoreSiteError extends CoreError {
|
|||
|
||||
errorcode?: string;
|
||||
errorDetails?: string;
|
||||
contactSupport?: boolean;
|
||||
siteConfig?: CoreSitePublicConfigResponse;
|
||||
supportConfig?: CoreUserSupportConfig;
|
||||
|
||||
constructor(options: CoreSiteErrorOptions) {
|
||||
super(getErrorMessage(options));
|
||||
|
||||
this.errorcode = options.errorcode;
|
||||
this.errorDetails = options.errorDetails;
|
||||
this.contactSupport = options.contactSupport;
|
||||
this.siteConfig = options.siteConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a url to contact site support.
|
||||
*
|
||||
* @returns Support page url.
|
||||
*/
|
||||
getSupportPageUrl(): string {
|
||||
if (!this.siteConfig) {
|
||||
throw new CoreError('Can\'t get support page url');
|
||||
}
|
||||
|
||||
return CoreUserSupport.getSupportPageUrl(this.siteConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the handling of this error allows users to contact support or not.
|
||||
*
|
||||
* @returns Whether to contact support or not.
|
||||
*/
|
||||
canContactSupport(): boolean {
|
||||
if (!this.contactSupport || !this.siteConfig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CoreUserSupport.canContactSupport(this.siteConfig);
|
||||
this.supportConfig = options.supportConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -70,10 +41,7 @@ export class CoreSiteError extends CoreError {
|
|||
* @returns Error message.
|
||||
*/
|
||||
function getErrorMessage(options: CoreSiteErrorOptions): string {
|
||||
if (
|
||||
options.contactSupport &&
|
||||
(!options.siteConfig || !CoreUserSupport.canContactSupport(options.siteConfig))
|
||||
) {
|
||||
if ('supportConfig' in options && !options.supportConfig?.canContactSupport()) {
|
||||
return options.fallbackMessage ?? options.message;
|
||||
}
|
||||
|
||||
|
@ -85,6 +53,8 @@ export type CoreSiteErrorOptions = {
|
|||
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.
|
||||
contactSupport?: boolean; // Whether this error warrants contacting site support or not.
|
||||
siteConfig?: CoreSitePublicConfigResponse;
|
||||
|
||||
// Configuration to use to contact site support. If this attribute is present, it means
|
||||
// that the error warrants contacting support.
|
||||
supportConfig?: CoreUserSupportConfig;
|
||||
};
|
||||
|
|
|
@ -60,8 +60,8 @@ import {
|
|||
import { Observable, ObservableInput, ObservedValueOf, OperatorFunction, Subject } from 'rxjs';
|
||||
import { finalize, map, mergeMap } from 'rxjs/operators';
|
||||
import { firstValueFrom } from '../utils/rxjs';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
|
||||
/**
|
||||
* QR Code type enumeration.
|
||||
|
@ -264,19 +264,6 @@ export class CoreSite {
|
|||
return this.db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get url to contact site support.
|
||||
*
|
||||
* @returns Site support page url.
|
||||
*/
|
||||
getSupportPageUrl(): string | null {
|
||||
if (!this.config || !this.canContactSupport()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CoreUserSupport.getSupportPageUrl(this.config, this.siteUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get site user's ID.
|
||||
*
|
||||
|
@ -436,19 +423,6 @@ export class CoreSite {
|
|||
return !!(info && (info.usercanmanageownfiles === undefined || info.usercanmanageownfiles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this site has a support url available.
|
||||
*
|
||||
* @returns Whether this site has a support url.
|
||||
*/
|
||||
canContactSupport(): boolean {
|
||||
if (this.isFeatureDisabled('NoDelegate_CoreUserSupport')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!this.config && CoreUserSupport.canContactSupport(this.config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user download files?
|
||||
*
|
||||
|
@ -1158,13 +1132,8 @@ export class CoreSite {
|
|||
);
|
||||
|
||||
if (!data || !data.responses) {
|
||||
const siteConfig = await CoreUtils.ignoreErrors(
|
||||
this.getPublicConfig({ readingStrategy: CoreSitesReadingStrategy.ONLY_CACHE }),
|
||||
);
|
||||
|
||||
throw new CoreSiteError({
|
||||
siteConfig,
|
||||
contactSupport: true,
|
||||
supportConfig: new CoreUserAuthenticatedSupportConfig(this),
|
||||
message: Translate.instant('core.cannotconnecttrouble'),
|
||||
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
|
||||
errorcode: 'invalidresponse',
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { CoreSiteConfig } from '@classes/site';
|
||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
|
||||
@Component({
|
||||
|
@ -23,8 +23,7 @@ import { CoreUserSupport } from '@features/user/services/support';
|
|||
})
|
||||
export class CoreLoginExceededAttemptsComponent implements OnInit {
|
||||
|
||||
@Input() siteUrl!: string;
|
||||
@Input() siteConfig!: CoreSiteConfig;
|
||||
@Input() supportConfig!: CoreUserSupportConfig;
|
||||
@Input() supportSubject?: string;
|
||||
|
||||
canContactSupport = false;
|
||||
|
@ -33,19 +32,15 @@ export class CoreLoginExceededAttemptsComponent implements OnInit {
|
|||
* @inheritdoc
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.canContactSupport = CoreUserSupport.canContactSupport(this.siteConfig);
|
||||
this.canContactSupport = this.supportConfig.canContactSupport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contact site support.
|
||||
*/
|
||||
async contactSupport(): Promise<void> {
|
||||
if (!this.siteConfig) {
|
||||
throw new Error('Can\'t contact support without config');
|
||||
}
|
||||
|
||||
await CoreUserSupport.contact({
|
||||
supportPageUrl: CoreUserSupport.getSupportPageUrl(this.siteConfig, this.siteUrl),
|
||||
supportConfig: this.supportConfig,
|
||||
subject: this.supportSubject,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
import { AlertButton } from '@ionic/angular';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
|
||||
/**
|
||||
* Page that shows instructions to change the password.
|
||||
|
@ -48,14 +49,14 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
|
|||
* Show a help modal.
|
||||
*/
|
||||
showHelp(): void {
|
||||
const site = CoreSites.getRequiredCurrentSite();
|
||||
const supportConfig = CoreUserAuthenticatedSupportConfig.forCurrentSite();
|
||||
const buttons: (AlertButton | string)[] = [];
|
||||
|
||||
if (site.canContactSupport()) {
|
||||
if (supportConfig.canContactSupport()) {
|
||||
buttons.push({
|
||||
text: Translate.instant('core.contactsupport'),
|
||||
handler: () => CoreUserSupport.contact({
|
||||
supportPageUrl: site.getSupportPageUrl(),
|
||||
supportConfig,
|
||||
subject: Translate.instant('core.login.changepasswordsupportsubject'),
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<p class="core-siteurl">{{siteUrl}}</p>
|
||||
</div>
|
||||
|
||||
<core-login-exceeded-attempts *ngIf="loginAttempts >= 3" [siteConfig]="siteConfig" [siteUrl]="siteUrl"
|
||||
<core-login-exceeded-attempts *ngIf="supportConfig && loginAttempts >= 3" [supportConfig]="supportConfig"
|
||||
[supportSubject]="'core.login.exceededloginattemptssupportsubject' | translate">
|
||||
{{ 'core.login.exceededloginattempts' | translate }}
|
||||
</core-login-exceeded-attempts>
|
||||
|
|
|
@ -29,6 +29,8 @@ import { CoreEvents } from '@singletons/events';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreForms } from '@singletons/form';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
|
||||
|
||||
/**
|
||||
* Page to enter the user credentials.
|
||||
|
@ -56,9 +58,10 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
showForgottenPassword = true;
|
||||
showScanQR = false;
|
||||
loginAttempts = 0;
|
||||
siteConfig?: CoreSitePublicConfigResponse;
|
||||
supportConfig?: CoreUserSupportConfig;
|
||||
canContactSupport?: boolean;
|
||||
|
||||
protected siteConfig?: CoreSitePublicConfigResponse;
|
||||
protected eventThrown = false;
|
||||
protected viewLeft = false;
|
||||
protected siteId?: string;
|
||||
|
@ -75,12 +78,12 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
async ngOnInit(): Promise<void> {
|
||||
try {
|
||||
this.siteUrl = CoreNavigator.getRequiredRouteParam<string>('siteUrl');
|
||||
|
||||
this.siteName = CoreNavigator.getRouteParam('siteName');
|
||||
this.logoUrl = !CoreConstants.CONFIG.forceLoginLogo && CoreNavigator.getRouteParam('logoUrl') || undefined;
|
||||
this.siteConfig = CoreNavigator.getRouteParam('siteConfig');
|
||||
this.siteConfig = CoreNavigator.getRouteParam<CoreSitePublicConfigResponse>('siteConfig');
|
||||
this.urlToOpen = CoreNavigator.getRouteParam('urlToOpen');
|
||||
this.canContactSupport = this.siteConfig && CoreUserSupport.canContactSupport(this.siteConfig);
|
||||
this.supportConfig = this.siteConfig && new CoreUserGuestSupportConfig(this.siteConfig);
|
||||
this.canContactSupport = this.supportConfig?.canContactSupport();
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModal(error);
|
||||
|
||||
|
@ -132,9 +135,11 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
* Contact site support.
|
||||
*/
|
||||
async contactSupport(): Promise<void> {
|
||||
const supportPageUrl = this.siteConfig && CoreUserSupport.getSupportPageUrl(this.siteConfig);
|
||||
if (!this.supportConfig) {
|
||||
throw new Error('can\'t contact support');
|
||||
}
|
||||
|
||||
await CoreUserSupport.contact({ supportPageUrl });
|
||||
await CoreUserSupport.contact({ supportConfig: this.supportConfig });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</ion-header>
|
||||
<ion-content>
|
||||
<div class="list-item-limited-width">
|
||||
<core-login-exceeded-attempts *ngIf="wasPasswordResetRequestedRecently" [siteConfig]="siteConfig" [siteUrl]="siteUrl"
|
||||
<core-login-exceeded-attempts *ngIf="supportConfig && wasPasswordResetRequestedRecently" [supportConfig]="supportConfig"
|
||||
[supportSubject]="'core.login.exceededpasswordresetattemptssupportsubject' | translate">
|
||||
{{ 'core.login.exceededpasswordresetattempts' | translate }}
|
||||
</core-login-exceeded-attempts>
|
||||
|
|
|
@ -23,6 +23,8 @@ import { CoreNavigator } from '@services/navigator';
|
|||
import { CoreForms } from '@singletons/form';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreSitePublicConfigResponse } from '@classes/site';
|
||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
|
||||
|
||||
/**
|
||||
* Page to recover a forgotten password.
|
||||
|
@ -37,8 +39,8 @@ export class CoreLoginForgottenPasswordPage implements OnInit {
|
|||
|
||||
myForm!: FormGroup;
|
||||
siteUrl!: string;
|
||||
siteConfig?: CoreSitePublicConfigResponse;
|
||||
autoFocus!: boolean;
|
||||
supportConfig?: CoreUserSupportConfig;
|
||||
wasPasswordResetRequestedRecently = false;
|
||||
|
||||
constructor(protected formBuilder: FormBuilder) {}
|
||||
|
@ -55,14 +57,16 @@ export class CoreLoginForgottenPasswordPage implements OnInit {
|
|||
return;
|
||||
}
|
||||
|
||||
const siteConfig = CoreNavigator.getRouteParam<CoreSitePublicConfigResponse>('siteConfig');
|
||||
|
||||
this.siteUrl = siteUrl;
|
||||
this.siteConfig = CoreNavigator.getRouteParam<CoreSitePublicConfigResponse>('siteConfig');
|
||||
this.autoFocus = CorePlatform.is('tablet');
|
||||
this.myForm = this.formBuilder.group({
|
||||
field: ['username', Validators.required],
|
||||
value: [CoreNavigator.getRouteParam<string>('username') || '', Validators.required],
|
||||
});
|
||||
|
||||
this.supportConfig = siteConfig && new CoreUserGuestSupportConfig(siteConfig);
|
||||
this.wasPasswordResetRequestedRecently = await CoreLoginHelper.wasPasswordResetRequestedRecently(siteUrl);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<core-login-exceeded-attempts *ngIf="reconnectAttempts >= 3" [siteConfig]="siteConfig" [siteUrl]="siteUrl"
|
||||
<core-login-exceeded-attempts *ngIf="supportConfig && reconnectAttempts >= 3" [supportConfig]="supportConfig"
|
||||
[supportSubject]="'core.login.exceededloginattemptssupportsubject' | translate">
|
||||
{{ 'core.login.exceededloginattempts' | translate }}
|
||||
</core-login-exceeded-attempts>
|
||||
|
|
|
@ -27,6 +27,8 @@ import { CoreError } from '@classes/errors/error';
|
|||
import { CoreNavigator, CoreRedirectPayload } from '@services/navigator';
|
||||
import { CoreForms } from '@singletons/form';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
|
||||
/**
|
||||
* Page to enter the user password to reconnect to a site.
|
||||
|
@ -57,9 +59,10 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
showScanQR = false;
|
||||
showLoading = true;
|
||||
reconnectAttempts = 0;
|
||||
siteConfig?: CoreSitePublicConfigResponse;
|
||||
supportConfig?: CoreUserSupportConfig;
|
||||
canContactSupport?: boolean;
|
||||
|
||||
protected siteConfig?: CoreSitePublicConfigResponse;
|
||||
protected viewLeft = false;
|
||||
protected eventThrown = false;
|
||||
protected redirectData?: CoreRedirectPayload;
|
||||
|
@ -104,7 +107,8 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
this.userAvatar = site.infos.userpictureurl;
|
||||
this.siteUrl = site.infos.siteurl;
|
||||
this.siteName = site.getSiteName();
|
||||
this.canContactSupport = site.canContactSupport();
|
||||
this.supportConfig = new CoreUserAuthenticatedSupportConfig(site);
|
||||
this.canContactSupport = this.supportConfig.canContactSupport();
|
||||
|
||||
// If login was OAuth we should only reach this page if the OAuth method ID has changed.
|
||||
this.isOAuth = site.isOAuth();
|
||||
|
@ -141,9 +145,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
* Contact site support.
|
||||
*/
|
||||
async contactSupport(): Promise<void> {
|
||||
const supportPageUrl = this.siteConfig && CoreUserSupport.getSupportPageUrl(this.siteConfig);
|
||||
|
||||
await CoreUserSupport.contact({ supportPageUrl });
|
||||
await CoreUserSupport.contact({ supportConfig: this.supportConfig });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -43,6 +43,8 @@ import { AlertButton } from '@ionic/core';
|
|||
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||
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';
|
||||
|
||||
/**
|
||||
* Site (url) chooser when adding a new site.
|
||||
|
@ -386,15 +388,15 @@ export class CoreLoginSitePage implements OnInit {
|
|||
protected async showLoginIssue(url: string | null, error: CoreError): Promise<void> {
|
||||
let errorMessage = CoreDomUtils.getErrorMessage(error);
|
||||
let siteExists = false;
|
||||
let supportPageUrl: string | null = null;
|
||||
let supportConfig: CoreUserSupportConfig | undefined = undefined;
|
||||
let errorDetails: string | undefined;
|
||||
let errorCode: string | undefined;
|
||||
|
||||
if (error instanceof CoreSiteError) {
|
||||
siteExists = !!error.siteConfig;
|
||||
supportPageUrl = error.canContactSupport() ? error.getSupportPageUrl() : null;
|
||||
supportConfig = error.supportConfig;
|
||||
errorDetails = error.errorDetails;
|
||||
errorCode = error.errorcode;
|
||||
siteExists = supportConfig instanceof CoreUserGuestSupportConfig;
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -420,12 +422,13 @@ export class CoreLoginSitePage implements OnInit {
|
|||
errorMessage += '<div class="core-error-info-container"></div>';
|
||||
}
|
||||
|
||||
const alertSupportConfig = supportConfig;
|
||||
const buttons: AlertButton[] = [
|
||||
supportPageUrl
|
||||
alertSupportConfig
|
||||
? {
|
||||
text: Translate.instant('core.contactsupport'),
|
||||
handler: () => CoreUserSupport.contact({
|
||||
supportPageUrl,
|
||||
supportConfig: alertSupportConfig,
|
||||
subject: Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
|
||||
message: `Error: ${errorCode}\n\n${errorDetails}`,
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,7 @@ import { CoreSite, CoreSiteInfo } from '@classes/site';
|
|||
import { CoreFilter } from '@features/filter/services/filter';
|
||||
import { CoreLoginSitesComponent } from '@features/login/components/sites/sites';
|
||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
import { CoreUser, CoreUserProfile } from '@features/user/services/user';
|
||||
import {
|
||||
|
@ -67,7 +68,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
|
|||
this.siteName = currentSite.getSiteName();
|
||||
this.siteUrl = currentSite.getURL();
|
||||
this.displaySwitchAccount = !currentSite.isFeatureDisabled('NoDelegate_SwitchAccount');
|
||||
this.displayContactSupport = currentSite.canContactSupport();
|
||||
this.displayContactSupport = new CoreUserAuthenticatedSupportConfig(currentSite).canContactSupport();
|
||||
this.removeAccountOnLogout = !!CoreConstants.CONFIG.removeaccountonlogout;
|
||||
|
||||
this.loadSiteLogo(currentSite);
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// (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 { CoreSite } from '@classes/site';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUserSupportConfig } from './support-config';
|
||||
|
||||
/**
|
||||
* Support config for an authenticated user.
|
||||
*/
|
||||
export class CoreUserAuthenticatedSupportConfig extends CoreUserSupportConfig {
|
||||
|
||||
/**
|
||||
* Get config for the current site.
|
||||
*
|
||||
* @returns Support config.
|
||||
*/
|
||||
static forCurrentSite(): CoreUserAuthenticatedSupportConfig {
|
||||
return new CoreUserAuthenticatedSupportConfig(CoreSites.getRequiredCurrentSite());
|
||||
}
|
||||
|
||||
private site: CoreSite;
|
||||
|
||||
constructor(site: CoreSite) {
|
||||
super();
|
||||
|
||||
this.site = site;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
canContactSupport(): boolean {
|
||||
return this.site.isVersionGreaterEqualThan('4.0')
|
||||
&& !this.site.isFeatureDisabled('NoDelegate_CoreUserSupport');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected buildSupportPageUrl(): string {
|
||||
return this.site.config?.supportpage?.trim()
|
||||
|| `${this.site.config?.httpswwwroot ?? this.site.config?.wwwroot ?? this.site.siteUrl}/user/contactsitesupport.php`;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
// (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 { CoreSitePublicConfigResponse } from '@classes/site';
|
||||
import { CoreUserNullSupportConfig } from '@features/user/classes/support/null-support-config';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreUserSupportConfig } from './support-config';
|
||||
|
||||
/**
|
||||
* Support config for a guest user.
|
||||
*/
|
||||
export class CoreUserGuestSupportConfig extends CoreUserSupportConfig {
|
||||
|
||||
/**
|
||||
* Get support config for a site with given url.
|
||||
*
|
||||
* @param siteUrl Site url.
|
||||
* @returns Support config.
|
||||
*/
|
||||
static async forSite(siteUrl: string): Promise<CoreUserSupportConfig> {
|
||||
const siteConfig = await CoreUtils.ignoreErrors(CoreSites.getPublicSiteConfigByUrl(siteUrl));
|
||||
|
||||
if (!siteConfig) {
|
||||
return new CoreUserNullSupportConfig();
|
||||
}
|
||||
|
||||
return new CoreUserGuestSupportConfig(siteConfig);
|
||||
}
|
||||
|
||||
private config: CoreSitePublicConfigResponse;
|
||||
|
||||
constructor(config: CoreSitePublicConfigResponse) {
|
||||
super();
|
||||
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
canContactSupport(): boolean {
|
||||
return 'supportpage' in this.config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected buildSupportPageUrl(): string {
|
||||
return this.config.supportpage?.trim()
|
||||
|| `${this.config.httpswwwroot || this.config.wwwroot}/user/contactsitesupport.php`;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// (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 { CoreUserSupportConfig } from './support-config';
|
||||
|
||||
/**
|
||||
* Null representation for a support config object.
|
||||
*
|
||||
* This class can be used in place of a functional support config when it's hasn't been possible
|
||||
* to obtain any site configuration to extract information about support.
|
||||
*/
|
||||
export class CoreUserNullSupportConfig extends CoreUserSupportConfig {
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
canContactSupport(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected buildSupportPageUrl(): string {
|
||||
throw new Error('Can\'t build a support page url from a null config');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// (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.
|
||||
|
||||
/**
|
||||
* Encapsulates the support affordances a user has access to.
|
||||
*/
|
||||
export abstract class CoreUserSupportConfig {
|
||||
|
||||
/**
|
||||
* Check whether the user can contact support or not.
|
||||
*
|
||||
* @return Whether the user can contact support.
|
||||
*/
|
||||
public abstract canContactSupport(): boolean;
|
||||
|
||||
/**
|
||||
* Get url to use for contacting support.
|
||||
*
|
||||
* @returns Support page url.
|
||||
*/
|
||||
getSupportPageUrl(): string {
|
||||
if (!this.canContactSupport()) {
|
||||
throw new Error('Can\'t get support page url');
|
||||
}
|
||||
|
||||
return this.buildSupportPageUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build page url string with the internal information.
|
||||
*
|
||||
* @return Support page url.
|
||||
*/
|
||||
protected abstract buildSupportPageUrl(): string;
|
||||
|
||||
}
|
|
@ -23,6 +23,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { AlertButton } from '@ionic/angular';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
|
||||
/**
|
||||
* Page that shows instructions to complete the profile.
|
||||
|
@ -47,14 +48,14 @@ export class CoreUserCompleteProfilePage implements OnDestroy {
|
|||
* Show a help modal.
|
||||
*/
|
||||
showHelp(): void {
|
||||
const site = CoreSites.getRequiredCurrentSite();
|
||||
const supportConfig = CoreUserAuthenticatedSupportConfig.forCurrentSite();
|
||||
const buttons: (AlertButton | string)[] = [];
|
||||
|
||||
if (site.canContactSupport()) {
|
||||
if (supportConfig.canContactSupport()) {
|
||||
buttons.push({
|
||||
text: Translate.instant('core.contactsupport'),
|
||||
handler: () => CoreUserSupport.contact({
|
||||
supportPageUrl: site.getSupportPageUrl(),
|
||||
supportConfig,
|
||||
subject: Translate.instant('core.login.completeprofilesupportsubject'),
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreSiteConfig, CoreSitePublicConfigResponse } from '@classes/site';
|
||||
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
import { InAppBrowserObject } from '@ionic-native/in-app-browser';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreSites } from '@services/sites';
|
||||
|
@ -35,12 +35,8 @@ export class CoreUserSupportService {
|
|||
* @param options Options to configure the interaction with support.
|
||||
*/
|
||||
async contact(options: CoreUserSupportContactOptions = {}): Promise<void> {
|
||||
const supportPageUrl = options.supportPageUrl ?? CoreSites.getRequiredCurrentSite().getSupportPageUrl();
|
||||
|
||||
if (!supportPageUrl) {
|
||||
throw new CoreError('Could not get support url');
|
||||
}
|
||||
|
||||
const supportConfig = options.supportConfig ?? CoreUserAuthenticatedSupportConfig.forCurrentSite();
|
||||
const supportPageUrl = supportConfig.getSupportPageUrl();
|
||||
const autoLoginUrl = await CoreSites.getCurrentSite()?.getAutoLoginUrl(supportPageUrl, false);
|
||||
const browser = CoreUtils.openInApp(autoLoginUrl ?? supportPageUrl);
|
||||
|
||||
|
@ -51,29 +47,6 @@ export class CoreUserSupportService {
|
|||
await CoreEvents.waitUntil(CoreEvents.IAB_EXIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get support page url from site config.
|
||||
*
|
||||
* @param config Site config.
|
||||
* @returns Support page url.
|
||||
*/
|
||||
getSupportPageUrl(config: CoreSitePublicConfigResponse): string;
|
||||
getSupportPageUrl(config: CoreSiteConfig, siteUrl: string): string;
|
||||
getSupportPageUrl(config: CoreSiteConfig | CoreSitePublicConfigResponse, siteUrl?: string): string {
|
||||
return config.supportpage?.trim()
|
||||
|| `${config.httpswwwroot ?? config.wwwroot ?? siteUrl}/user/contactsitesupport.php`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a site config allows contacting support.
|
||||
*
|
||||
* @param config Site config.
|
||||
* @returns Whether site support can be contacted.
|
||||
*/
|
||||
canContactSupport(config: CoreSiteConfig | CoreSitePublicConfigResponse): boolean {
|
||||
return 'supportpage' in config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject error details into contact support form.
|
||||
*
|
||||
|
@ -106,7 +79,7 @@ export const CoreUserSupport = makeSingleton(CoreUserSupportService);
|
|||
* Options to configure interaction with support.
|
||||
*/
|
||||
export interface CoreUserSupportContactOptions {
|
||||
supportPageUrl?: string | null;
|
||||
supportConfig?: CoreUserSupportConfig | null;
|
||||
subject?: string | null;
|
||||
message?: string | null;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
|
||||
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
import { CoreUserNullSupportConfig } from '@features/user/classes/support/null-support-config';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
|
@ -47,7 +50,9 @@ export default function(): void {
|
|||
// It's an SSO token for another app. Close the IAB and show an error.
|
||||
CoreUtils.closeInAppBrowser();
|
||||
CoreDomUtils.showErrorModal(new CoreSiteError({
|
||||
contactSupport: true,
|
||||
supportConfig: CoreSites.getCurrentSite()
|
||||
? CoreUserAuthenticatedSupportConfig.forCurrentSite()
|
||||
: new CoreUserNullSupportConfig(),
|
||||
message: Translate.instant('core.cannotconnecttrouble'),
|
||||
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
|
||||
errorcode: 'invalidurlscheme',
|
||||
|
|
|
@ -61,6 +61,7 @@ import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/da
|
|||
import { asyncInstance, AsyncInstance } from '../utils/async-instance';
|
||||
import { CoreConfig } from './config';
|
||||
import { CoreNetwork } from '@services/network';
|
||||
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
|
||||
|
||||
export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS');
|
||||
export const CORE_SITE_CURRENT_SITE_ID_CONFIG = 'current_site_id';
|
||||
|
@ -297,16 +298,16 @@ export class CoreSitesProvider {
|
|||
// Check that the user can authenticate.
|
||||
if (!config.enablewebservices) {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: new CoreUserGuestSupportConfig(config),
|
||||
errorcode: 'webservicesnotenabled',
|
||||
errorDetails: Translate.instant('core.login.webservicesnotenabled'),
|
||||
siteConfig: config,
|
||||
critical: true,
|
||||
});
|
||||
} else if (!config.enablemobilewebservice) {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: new CoreUserGuestSupportConfig(config),
|
||||
errorcode: 'mobileservicesnotenabled',
|
||||
errorDetails: Translate.instant('core.login.mobileservicesnotenabled'),
|
||||
siteConfig: config,
|
||||
critical: true,
|
||||
});
|
||||
} else if (config.maintenanceenabled) {
|
||||
|
@ -332,24 +333,12 @@ export class CoreSitesProvider {
|
|||
* @param options Error options.
|
||||
* @return Cannot connect error.
|
||||
*/
|
||||
protected createCannotConnectLoginError(options?: Partial<CoreLoginErrorOptions>): CoreLoginError;
|
||||
protected createCannotConnectLoginError(siteUrl: string, options?: Partial<CoreLoginErrorOptions>): Promise<CoreLoginError>;
|
||||
protected createCannotConnectLoginError(
|
||||
siteUrlOrOptions: string | Partial<CoreLoginErrorOptions> = {},
|
||||
options: Partial<CoreLoginErrorOptions> = {},
|
||||
): CoreLoginError | Promise<CoreLoginError> {
|
||||
const createError = (options: Partial<CoreLoginErrorOptions>) => new CoreLoginError({
|
||||
protected createCannotConnectLoginError(options?: Partial<CoreLoginErrorOptions>): CoreLoginError {
|
||||
return new CoreLoginError({
|
||||
...options,
|
||||
message: Translate.instant('core.cannotconnecttrouble'),
|
||||
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
|
||||
contactSupport: true,
|
||||
});
|
||||
|
||||
return typeof siteUrlOrOptions === 'object'
|
||||
? createError(siteUrlOrOptions)
|
||||
: CoreUtils
|
||||
.ignoreErrors(this.getPublicSiteConfigByUrl(siteUrlOrOptions))
|
||||
.then(siteConfig => createError({ ...options, siteConfig }));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -376,8 +365,7 @@ export class CoreSitesProvider {
|
|||
critical: true,
|
||||
message: error.message,
|
||||
errorcode: error.errorcode,
|
||||
contactSupport: error.contactSupport,
|
||||
siteConfig: error.siteConfig,
|
||||
supportConfig: error.supportConfig,
|
||||
errorDetails: error.errorDetails,
|
||||
};
|
||||
|
||||
|
@ -425,7 +413,8 @@ export class CoreSitesProvider {
|
|||
data = await Http.post(siteUrl + '/login/token.php', { appsitecheck: 1 }).pipe(timeout(CoreWS.getRequestTimeout()))
|
||||
.toPromise();
|
||||
} catch (error) {
|
||||
throw await this.createCannotConnectLoginError(siteUrl, {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
errorcode: 'sitecheckfailed',
|
||||
errorDetails: CoreDomUtils.getErrorMessage(error) ?? undefined,
|
||||
});
|
||||
|
@ -433,14 +422,16 @@ export class CoreSitesProvider {
|
|||
|
||||
if (data === null) {
|
||||
// Cannot connect.
|
||||
throw await this.createCannotConnectLoginError(siteUrl, {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
errorcode: 'appsitecheckfailed',
|
||||
errorDetails: 'A request to /login/token.php with appsitecheck=1 returned an empty response',
|
||||
});
|
||||
}
|
||||
|
||||
if (data.errorcode && (data.errorcode == 'enablewsdescription' || data.errorcode == 'requirecorrectaccess')) {
|
||||
throw await this.createCannotConnectLoginError(siteUrl, {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
critical: data.errorcode == 'enablewsdescription',
|
||||
errorcode: data.errorcode,
|
||||
errorDetails: data.error,
|
||||
|
@ -448,7 +439,8 @@ export class CoreSitesProvider {
|
|||
}
|
||||
|
||||
if (data.error && data.error == 'Web services must be enabled in Advanced features.') {
|
||||
throw await this.createCannotConnectLoginError(siteUrl, {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
critical: true,
|
||||
errorcode: 'enablewsdescription',
|
||||
errorDetails: data.error,
|
||||
|
@ -511,14 +503,16 @@ export class CoreSitesProvider {
|
|||
const redirect = await CoreUtils.checkRedirect(loginUrl);
|
||||
|
||||
if (redirect) {
|
||||
throw await this.createCannotConnectLoginError(siteUrl, {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
errorcode: 'sitehasredirect',
|
||||
errorDetails: Translate.instant('core.login.sitehasredirect'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
throw await this.createCannotConnectLoginError(siteUrl, {
|
||||
throw this.createCannotConnectLoginError({
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
errorcode: data.errorcode,
|
||||
errorDetails: data.error,
|
||||
});
|
||||
|
|
|
@ -1366,11 +1366,12 @@ export class CoreDomUtilsProvider {
|
|||
alertOptions.message += '<div class="core-error-info-container"></div>';
|
||||
}
|
||||
|
||||
if (error.canContactSupport()) {
|
||||
const supportConfig = error.supportConfig;
|
||||
if (supportConfig?.canContactSupport()) {
|
||||
alertOptions.buttons.push({
|
||||
text: Translate.instant('core.contactsupport'),
|
||||
handler: () => CoreUserSupport.contact({
|
||||
supportPageUrl: error.getSupportPageUrl(),
|
||||
supportConfig,
|
||||
subject: alertOptions.header,
|
||||
message: `${error.errorcode}\n\n${error.errorDetails}`,
|
||||
}),
|
||||
|
|
|
@ -39,9 +39,8 @@ import { CoreSite } from '@classes/site';
|
|||
import { CoreHttpError } from '@classes/errors/httperror';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror';
|
||||
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
|
||||
|
||||
/**
|
||||
* This service allows performing WS calls and download/upload files.
|
||||
|
@ -470,11 +469,8 @@ 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 siteConfig = await CoreUtils.ignoreErrors(CoreSites.getPublicSiteConfigByUrl(preSets.siteUrl));
|
||||
|
||||
throw new CoreAjaxError({
|
||||
siteConfig,
|
||||
contactSupport: true,
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(preSets.siteUrl),
|
||||
message: Translate.instant('core.cannotconnecttrouble'),
|
||||
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
|
||||
errorcode: 'invalidresponse',
|
||||
|
@ -496,8 +492,7 @@ export class CoreWSProvider {
|
|||
return data.data;
|
||||
}, async (data: HttpErrorResponse) => {
|
||||
const options: CoreSiteErrorOptions = {
|
||||
contactSupport: true,
|
||||
siteConfig: await CoreUtils.ignoreErrors(CoreSites.getPublicSiteConfigByUrl(preSets.siteUrl)),
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(preSets.siteUrl),
|
||||
message: Translate.instant('core.cannotconnecttrouble'),
|
||||
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
|
||||
};
|
||||
|
@ -1132,14 +1127,11 @@ export class CoreWSProvider {
|
|||
siteUrl: string,
|
||||
options?: Partial<CoreSiteErrorOptions>,
|
||||
): Promise<CoreSiteError> {
|
||||
const siteConfig = await CoreUtils.ignoreErrors(CoreSites.getPublicSiteConfigByUrl(siteUrl));
|
||||
|
||||
return new CoreSiteError({
|
||||
...options,
|
||||
siteConfig,
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
message: Translate.instant('core.cannotconnecttrouble'),
|
||||
fallbackMessage: Translate.instant('core.cannotconnecttroublewithoutsupport'),
|
||||
contactSupport: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue