forked from CIT/Vmeda.Online
		
	Merge pull request #3560 from alfonso-salces/MOBILE-4245
[4.2] Mobile 4245 - Add new config.json setting to allow to specify staging sites for testing purposes
This commit is contained in:
		
						commit
						874f47ebad
					
				@ -85,8 +85,7 @@
 | 
			
		||||
        "high": 120
 | 
			
		||||
    },
 | 
			
		||||
    "customurlscheme": "moodlemobile",
 | 
			
		||||
    "siteurl": "",
 | 
			
		||||
    "sitename": "",
 | 
			
		||||
    "sites": [],
 | 
			
		||||
    "multisitesdisplay": "",
 | 
			
		||||
    "sitefindersettings": {},
 | 
			
		||||
    "onlyallowlistedsites": false,
 | 
			
		||||
 | 
			
		||||
@ -261,7 +261,8 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy
 | 
			
		||||
        event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const siteName = CoreSites.getRequiredCurrentSite().getSiteName();
 | 
			
		||||
            const site = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
            const siteName = await site.getSiteName();
 | 
			
		||||
 | 
			
		||||
            this.spaceUsage = await CoreSettingsHelper.deleteSiteStorage(siteName, this.siteId);
 | 
			
		||||
        } catch {
 | 
			
		||||
 | 
			
		||||
@ -61,6 +61,7 @@ import { finalize, map, mergeMap } from 'rxjs/operators';
 | 
			
		||||
import { firstValueFrom } from '../utils/rxjs';
 | 
			
		||||
import { CoreSiteError } from '@classes/errors/siteerror';
 | 
			
		||||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
 | 
			
		||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * QR Code type enumeration.
 | 
			
		||||
@ -289,13 +290,21 @@ export class CoreSite {
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Site name.
 | 
			
		||||
     */
 | 
			
		||||
    getSiteName(): string {
 | 
			
		||||
        if (CoreConstants.CONFIG.sitename) {
 | 
			
		||||
            // Overridden by config.
 | 
			
		||||
            return CoreConstants.CONFIG.sitename;
 | 
			
		||||
        } else {
 | 
			
		||||
            return this.infos?.sitename || '';
 | 
			
		||||
    async getSiteName(): Promise<string> {
 | 
			
		||||
        if (this.infos?.sitename) {
 | 
			
		||||
            return this.infos?.sitename;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fallback.
 | 
			
		||||
        const isSigleFixedSite = await CoreLoginHelper.isSingleFixedSite();
 | 
			
		||||
 | 
			
		||||
        if (isSigleFixedSite) {
 | 
			
		||||
            const sites = await CoreLoginHelper.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
            return sites[0].name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -65,9 +65,14 @@ export class CoreShowPasswordComponent implements OnInit, AfterViewInit {
 | 
			
		||||
     */
 | 
			
		||||
    async ngAfterViewInit(): Promise<void> {
 | 
			
		||||
        if (this.ionInput) {
 | 
			
		||||
            // It's an ion-input, use it to get the native element.
 | 
			
		||||
            this.input = await this.ionInput.getInputElement();
 | 
			
		||||
            this.setData(this.input);
 | 
			
		||||
            try {
 | 
			
		||||
                // It's an ion-input, use it to get the native element.
 | 
			
		||||
                this.input = await this.ionInput.getInputElement();
 | 
			
		||||
                this.setData(this.input);
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                // This should never fail, but it does in some testing environment because Ionic elements are not
 | 
			
		||||
                // rendered properly. So in case this fails, we'll just ignore the error.
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -61,9 +61,9 @@ export class CoreCoursesMyPage implements OnInit, OnDestroy, AsyncDirective {
 | 
			
		||||
 | 
			
		||||
    constructor(protected loadsManager: PageLoadsManager) {
 | 
			
		||||
        // Refresh the enabled flags if site is updated.
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, async () => {
 | 
			
		||||
            this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
 | 
			
		||||
            this.loadSiteName();
 | 
			
		||||
            await this.loadSiteName();
 | 
			
		||||
 | 
			
		||||
        }, CoreSites.getCurrentSiteId());
 | 
			
		||||
 | 
			
		||||
@ -78,13 +78,13 @@ export class CoreCoursesMyPage implements OnInit, OnDestroy, AsyncDirective {
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
 | 
			
		||||
 | 
			
		||||
        const deepLinkManager = new CoreMainMenuDeepLinkManager();
 | 
			
		||||
        deepLinkManager.treatLink();
 | 
			
		||||
 | 
			
		||||
        this.loadSiteName();
 | 
			
		||||
        await this.loadSiteName();
 | 
			
		||||
 | 
			
		||||
        this.loadContent(true);
 | 
			
		||||
    }
 | 
			
		||||
@ -143,8 +143,9 @@ export class CoreCoursesMyPage implements OnInit, OnDestroy, AsyncDirective {
 | 
			
		||||
    /**
 | 
			
		||||
     * Load the site name.
 | 
			
		||||
     */
 | 
			
		||||
    protected loadSiteName(): void {
 | 
			
		||||
        this.siteName = CoreSites.getRequiredCurrentSite().getSiteName() || '';
 | 
			
		||||
    protected async loadSiteName(): Promise<void> {
 | 
			
		||||
        const site = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
        this.siteName = await site.getSiteName() || '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ export class CoreLoginHasSitesGuard implements CanActivate, CanLoad {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const [path, params] = CoreLoginHelper.getAddSiteRouteInfo();
 | 
			
		||||
        const [path, params] = await CoreLoginHelper.getAddSiteRouteInfo();
 | 
			
		||||
        const route = Router.parseUrl(path);
 | 
			
		||||
 | 
			
		||||
        route.queryParams = params;
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
 | 
			
		||||
    identityProviders?: CoreSiteIdentityProvider[];
 | 
			
		||||
    pageLoaded = false;
 | 
			
		||||
    isBrowserSSO = false;
 | 
			
		||||
    isFixedUrlSet = false;
 | 
			
		||||
    showForgottenPassword = true;
 | 
			
		||||
    showScanQR = false;
 | 
			
		||||
    loginAttempts = 0;
 | 
			
		||||
@ -99,9 +98,10 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
 | 
			
		||||
        if (this.siteConfig) {
 | 
			
		||||
            this.treatSiteConfig();
 | 
			
		||||
        }
 | 
			
		||||
        this.isFixedUrlSet = CoreLoginHelper.isFixedUrlSet();
 | 
			
		||||
 | 
			
		||||
        if (this.isFixedUrlSet || !this.siteConfig) {
 | 
			
		||||
        const isSingleFixedSite = await CoreLoginHelper.isSingleFixedSite();
 | 
			
		||||
 | 
			
		||||
        if (isSingleFixedSite || !this.siteConfig) {
 | 
			
		||||
            // Fixed URL or not siteConfig retrieved from params, we need to check if it uses browser SSO login.
 | 
			
		||||
            this.checkSite(this.siteUrl, true);
 | 
			
		||||
        } else {
 | 
			
		||||
@ -198,12 +198,12 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
 | 
			
		||||
    /**
 | 
			
		||||
     * Treat the site configuration (if it exists).
 | 
			
		||||
     */
 | 
			
		||||
    protected treatSiteConfig(): void {
 | 
			
		||||
    protected async treatSiteConfig(): Promise<void> {
 | 
			
		||||
        if (this.siteConfig) {
 | 
			
		||||
            this.siteName = CoreConstants.CONFIG.sitename ? CoreConstants.CONFIG.sitename : this.siteConfig.sitename;
 | 
			
		||||
            this.siteName = this.siteConfig.sitename;
 | 
			
		||||
            this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
 | 
			
		||||
            this.authInstructions = this.siteConfig.authinstructions || Translate.instant('core.login.loginsteps');
 | 
			
		||||
            this.showScanQR = CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
 | 
			
		||||
            this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
 | 
			
		||||
 | 
			
		||||
            const disabledFeatures = CoreLoginHelper.getDisabledFeatures(this.siteConfig);
 | 
			
		||||
            this.identityProviders = CoreLoginHelper.getValidIdentityProviders(this.siteConfig, disabledFeatures);
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,6 @@ import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreTextUtils } from '@services/utils/text';
 | 
			
		||||
import { CoreCountry, CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreWS, CoreWSExternalWarning } from '@services/ws';
 | 
			
		||||
import { CoreConstants } from '@/core/constants';
 | 
			
		||||
import { Translate } from '@singletons';
 | 
			
		||||
import { CoreSitePublicConfigResponse } from '@classes/site';
 | 
			
		||||
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
 | 
			
		||||
@ -235,7 +234,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
 | 
			
		||||
     */
 | 
			
		||||
    protected treatSiteConfig(): boolean {
 | 
			
		||||
        if (this.siteConfig?.registerauth == 'email' && !CoreLoginHelper.isEmailSignupDisabled(this.siteConfig)) {
 | 
			
		||||
            this.siteName = CoreConstants.CONFIG.sitename ? CoreConstants.CONFIG.sitename : this.siteConfig.sitename;
 | 
			
		||||
            this.siteName = this.siteConfig.sitename;
 | 
			
		||||
            this.authInstructions = this.siteConfig.authinstructions;
 | 
			
		||||
            this.ageDigitalConsentVerification = this.siteConfig.agedigitalconsentverification;
 | 
			
		||||
            this.supportName = this.siteConfig.supportname;
 | 
			
		||||
 | 
			
		||||
@ -18,12 +18,12 @@
 | 
			
		||||
<ion-content class="ion-padding" (keydown)="keyDown($event)" (keyup)="keyUp($event)">
 | 
			
		||||
    <core-loading [hideUntil]="!showLoading">
 | 
			
		||||
        <div class="list-item-limited-width">
 | 
			
		||||
            <div class="ion-text-wrap ion-text-center ion-margin-bottom" [ngClass]="{'item-avatar-center': showSiteAvatar}">
 | 
			
		||||
            <div class="ion-text-wrap ion-text-center ion-margin-bottom" [ngClass]="{'item-avatar-center': showUserAvatar}">
 | 
			
		||||
                <!-- Show user avatar. -->
 | 
			
		||||
                <img *ngIf="showSiteAvatar" [src]="userAvatar" class="large-avatar" core-external-content [siteId]="siteId"
 | 
			
		||||
                <img *ngIf="showUserAvatar" [src]="userAvatar" class="large-avatar" core-external-content [siteId]="siteId"
 | 
			
		||||
                    alt="{{ 'core.pictureof' | translate:{$a: userFullName} }}" onError="this.src='assets/img/user-avatar.png'">
 | 
			
		||||
 | 
			
		||||
                <div class="core-login-site-logo" *ngIf="!showSiteAvatar">
 | 
			
		||||
                <div class="core-login-site-logo" *ngIf="!showUserAvatar">
 | 
			
		||||
                    <!-- Show site logo or a default image. -->
 | 
			
		||||
                    <img *ngIf="logoUrl" [src]="logoUrl" role="presentation" onError="this.src='assets/img/login_logo.png'" alt="">
 | 
			
		||||
                    <img *ngIf="!logoUrl" src="assets/img/login_logo.png" role="presentation" alt="">
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
 | 
			
		||||
    logoUrl?: string;
 | 
			
		||||
    identityProviders?: CoreSiteIdentityProvider[];
 | 
			
		||||
    showForgottenPassword = true;
 | 
			
		||||
    showSiteAvatar = false;
 | 
			
		||||
    showUserAvatar = false;
 | 
			
		||||
    isBrowserSSO = false;
 | 
			
		||||
    isOAuth = false;
 | 
			
		||||
    isLoggedOut: boolean;
 | 
			
		||||
@ -108,14 +108,16 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
 | 
			
		||||
            this.userFullName = site.infos.fullname;
 | 
			
		||||
            this.userAvatar = site.infos.userpictureurl;
 | 
			
		||||
            this.siteUrl = site.infos.siteurl;
 | 
			
		||||
            this.siteName = site.getSiteName();
 | 
			
		||||
            this.siteName = await site.getSiteName();
 | 
			
		||||
            this.supportConfig = new CoreUserAuthenticatedSupportConfig(site);
 | 
			
		||||
 | 
			
		||||
            // If login was OAuth we should only reach this page if the OAuth method ID has changed.
 | 
			
		||||
            this.isOAuth = site.isOAuth();
 | 
			
		||||
 | 
			
		||||
            const sites = await CoreLoginHelper.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
            // Show logo instead of avatar if it's a fixed site.
 | 
			
		||||
            this.showSiteAvatar = !!this.userAvatar && !CoreLoginHelper.getFixedSites();
 | 
			
		||||
            this.showUserAvatar = !!this.userAvatar && !sites.length;
 | 
			
		||||
 | 
			
		||||
            this.checkSiteConfig(site);
 | 
			
		||||
 | 
			
		||||
@ -180,14 +182,18 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.isBrowserSSO = !this.isOAuth && CoreLoginHelper.isSSOLoginNeeded(this.siteConfig.typeoflogin);
 | 
			
		||||
        this.showScanQR = CoreLoginHelper.displayQRInSiteScreen() ||
 | 
			
		||||
            CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
 | 
			
		||||
 | 
			
		||||
        this.showScanQR = CoreLoginHelper.displayQRInSiteScreen();
 | 
			
		||||
 | 
			
		||||
        if (!this.showScanQR) {
 | 
			
		||||
            this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await CoreSites.checkApplication(this.siteConfig);
 | 
			
		||||
 | 
			
		||||
        // Check logoURL if user avatar is not set.
 | 
			
		||||
        if (this.userAvatar?.startsWith(this.siteUrl + '/theme/image.php')) {
 | 
			
		||||
            this.showSiteAvatar = false;
 | 
			
		||||
            this.showUserAvatar = false;
 | 
			
		||||
        }
 | 
			
		||||
        this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@
 | 
			
		||||
        <div class="ion-text-center ion-padding ion-margin-bottom core-login-site-logo" [class.hidden]="hasSites || enteredSiteUrl">
 | 
			
		||||
            <img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
        <form [formGroup]="siteForm" (ngSubmit)="connect($event, siteForm.value.siteUrl)" *ngIf="!fixedSites" #siteFormEl>
 | 
			
		||||
        <form [formGroup]="siteForm" (ngSubmit)="connect($event, siteForm.value.siteUrl)" *ngIf="!fixedSites && siteForm" #siteFormEl>
 | 
			
		||||
            <!-- Form to input the site URL if there are no fixed sites. -->
 | 
			
		||||
            <ng-container *ngIf=" siteSelector=='url'">
 | 
			
		||||
                <ion-item>
 | 
			
		||||
@ -101,7 +101,8 @@
 | 
			
		||||
        </ng-container>
 | 
			
		||||
 | 
			
		||||
        <ng-container *ngIf="showScanQR && !hasSites && !enteredSiteUrl">
 | 
			
		||||
            <div class="ion-text-center ion-padding ion-margin-top core-login-site-qrcode-separator">{{ 'core.login.or' | translate }}</div>
 | 
			
		||||
            <div class="ion-text-center ion-padding ion-margin-top core-login-site-qrcode-separator">{{ 'core.login.or' | translate }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <ion-button expand="block" fill="outline" class="ion-margin core-login-site-qrcode" (click)="showInstructionsAndScanQR()"
 | 
			
		||||
                aria-haspopup="dialog">
 | 
			
		||||
                <ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
 | 
			
		||||
@ -119,7 +120,7 @@
 | 
			
		||||
 | 
			
		||||
<!-- Template site selector. -->
 | 
			
		||||
<ng-template #sitelisting let-site="site">
 | 
			
		||||
    <ion-item button (click)="connect($event, site.url, site)" [attr.aria-label]="site.name" detail="true">
 | 
			
		||||
    <ion-item button (click)="connect($event, site.url, site)" [ngClass]="site.className" [attr.aria-label]="site.name" detail="true">
 | 
			
		||||
        <ion-thumbnail *ngIf="siteFinderSettings.displayimage" slot="start">
 | 
			
		||||
            <img [src]="site.imageurl" *ngIf="site.imageurl" onError="this.src='assets/icon/icon.png'" alt="" role="presentation">
 | 
			
		||||
            <img src="assets/icon/icon.png" *ngIf="!site.imageurl" class="core-login-default-icon" alt="" role="presentation">
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ export class CoreLoginSitePage implements OnInit {
 | 
			
		||||
 | 
			
		||||
    @ViewChild('siteFormEl') formElement?: ElementRef;
 | 
			
		||||
 | 
			
		||||
    siteForm: FormGroup;
 | 
			
		||||
    siteForm!: FormGroup;
 | 
			
		||||
    fixedSites?: CoreLoginSiteInfoExtended[];
 | 
			
		||||
    filteredSites?: CoreLoginSiteInfoExtended[];
 | 
			
		||||
    siteSelector: CoreLoginSiteSelectorListMethod = 'sitefinder';
 | 
			
		||||
@ -68,15 +68,17 @@ export class CoreLoginSitePage implements OnInit {
 | 
			
		||||
    sites: CoreLoginSiteInfoExtended[] = [];
 | 
			
		||||
    hasSites = false;
 | 
			
		||||
    loadingSites = false;
 | 
			
		||||
    searchFunction: (search: string) => void;
 | 
			
		||||
    showScanQR: boolean;
 | 
			
		||||
    searchFunction!: (search: string) => void;
 | 
			
		||||
    showScanQR!: boolean;
 | 
			
		||||
    enteredSiteUrl?: CoreLoginSiteInfoExtended;
 | 
			
		||||
    siteFinderSettings: CoreLoginSiteFinderSettings;
 | 
			
		||||
    siteFinderSettings!: CoreLoginSiteFinderSettings;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        protected formBuilder: FormBuilder,
 | 
			
		||||
    ) {
 | 
			
		||||
    constructor(protected formBuilder: FormBuilder) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the component.
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        let url = '';
 | 
			
		||||
        this.siteSelector = CoreConstants.CONFIG.multisitesdisplay;
 | 
			
		||||
 | 
			
		||||
@ -92,8 +94,10 @@ export class CoreLoginSitePage implements OnInit {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Load fixed sites if they're set.
 | 
			
		||||
        if (CoreLoginHelper.hasSeveralFixedSites()) {
 | 
			
		||||
            url = this.initSiteSelector();
 | 
			
		||||
        const sites = await CoreLoginHelper.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
        if (sites.length) {
 | 
			
		||||
            url = await this.initSiteSelector();
 | 
			
		||||
        } else if (CoreConstants.CONFIG.enableonboarding && !CorePlatform.isIOS()) {
 | 
			
		||||
            this.initOnboarding();
 | 
			
		||||
        }
 | 
			
		||||
@ -122,12 +126,7 @@ export class CoreLoginSitePage implements OnInit {
 | 
			
		||||
 | 
			
		||||
            this.loadingSites = false;
 | 
			
		||||
        }, 1000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the component.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        this.showKeyboard = !!CoreNavigator.getRouteBooleanParam('showKeyboard');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -136,8 +135,9 @@ export class CoreLoginSitePage implements OnInit {
 | 
			
		||||
     *
 | 
			
		||||
     * @returns URL of the first site.
 | 
			
		||||
     */
 | 
			
		||||
    protected initSiteSelector(): string {
 | 
			
		||||
        this.fixedSites = this.extendCoreLoginSiteInfo(<CoreLoginSiteInfoExtended[]> CoreLoginHelper.getFixedSites());
 | 
			
		||||
    protected async initSiteSelector(): Promise<string> {
 | 
			
		||||
        const availableSites = await CoreLoginHelper.getAvailableSites();
 | 
			
		||||
        this.fixedSites = this.extendCoreLoginSiteInfo(<CoreLoginSiteInfoExtended[]> availableSites);
 | 
			
		||||
        this.siteSelector = 'list'; // In case it's not defined
 | 
			
		||||
 | 
			
		||||
        // Do not show images if none are set.
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ import { CorePath } from '@singletons/path';
 | 
			
		||||
import { CorePromisedValue } from '@classes/promised-value';
 | 
			
		||||
import { SafeHtml } from '@angular/platform-browser';
 | 
			
		||||
import { CoreLoginError } from '@classes/errors/loginerror';
 | 
			
		||||
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
 | 
			
		||||
 | 
			
		||||
const PASSWORD_RESETS_CONFIG_KEY = 'password-resets';
 | 
			
		||||
 | 
			
		||||
@ -379,9 +380,23 @@ export class CoreLoginHelperProvider {
 | 
			
		||||
     * Get fixed site or sites.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Fixed site or list of fixed sites.
 | 
			
		||||
     * @deprecated since 4.2.0. Use CoreConstants.CONFIG.sites or getAvailableSites() instead.
 | 
			
		||||
     */
 | 
			
		||||
    getFixedSites(): string | CoreLoginSiteInfo[] {
 | 
			
		||||
        return CoreConstants.CONFIG.siteurl;
 | 
			
		||||
        const notStagingSites = CoreConstants.CONFIG.sites.filter(site => !site.staging);
 | 
			
		||||
 | 
			
		||||
        return notStagingSites.length === 1 ? notStagingSites[0].url : notStagingSites;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get Available sites (includes staging sites if are enabled).
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Available sites.
 | 
			
		||||
     */
 | 
			
		||||
    async getAvailableSites(): Promise<CoreLoginSiteInfo[]> {
 | 
			
		||||
        const hasEnabledStagingSites = await CoreSettingsHelper.hasEnabledStagingSites();
 | 
			
		||||
 | 
			
		||||
        return hasEnabledStagingSites ? CoreConstants.CONFIG.sites : CoreConstants.CONFIG.sites.filter(site => !site.staging);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -440,7 +455,7 @@ export class CoreLoginHelperProvider {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            [path, params] = this.getAddSiteRouteInfo(showKeyboard);
 | 
			
		||||
            [path, params] = await this.getAddSiteRouteInfo(showKeyboard);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await CoreNavigator.navigate(path, { params, reset: setRoot });
 | 
			
		||||
@ -452,13 +467,12 @@ export class CoreLoginHelperProvider {
 | 
			
		||||
     * @param showKeyboard Whether to show keyboard in the new page. Only if no fixed URL set.
 | 
			
		||||
     * @returns Path and params.
 | 
			
		||||
     */
 | 
			
		||||
    getAddSiteRouteInfo(showKeyboard?: boolean): [string, Params] {
 | 
			
		||||
        if (this.isFixedUrlSet()) {
 | 
			
		||||
            // Fixed URL is set, go to credentials page.
 | 
			
		||||
            const fixedSites = this.getFixedSites();
 | 
			
		||||
            const url = typeof fixedSites == 'string' ? fixedSites : fixedSites[0].url;
 | 
			
		||||
    async getAddSiteRouteInfo(showKeyboard?: boolean): Promise<[string, Params]> {
 | 
			
		||||
        const sites = await this.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
            return ['/login/credentials', { siteUrl: url }];
 | 
			
		||||
        if (sites.length === 1) {
 | 
			
		||||
            // Fixed URL is set, go to credentials page.
 | 
			
		||||
            return ['/login/credentials', { siteUrl: sites[0].url }];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ['/login/site', { showKeyboard }];
 | 
			
		||||
@ -518,10 +532,12 @@ export class CoreLoginHelperProvider {
 | 
			
		||||
     * Check if the app is configured to use several fixed URLs.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Whether there are several fixed URLs.
 | 
			
		||||
     * @deprecated 4.2.0 Use CoreConstants.CONFIG.sites.length > 1 instead.
 | 
			
		||||
     */
 | 
			
		||||
    hasSeveralFixedSites(): boolean {
 | 
			
		||||
        return !!(CoreConstants.CONFIG.siteurl && Array.isArray(CoreConstants.CONFIG.siteurl) &&
 | 
			
		||||
            CoreConstants.CONFIG.siteurl.length > 1);
 | 
			
		||||
    async hasSeveralFixedSites(): Promise<boolean> {
 | 
			
		||||
        const sites = await this.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
        return sites.length > 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -557,13 +573,21 @@ export class CoreLoginHelperProvider {
 | 
			
		||||
     * Check if the app is configured to use a fixed URL (only 1).
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Whether there is 1 fixed URL.
 | 
			
		||||
     * @deprecated 4.2.0 Use isSingleFixedSite instead.
 | 
			
		||||
     */
 | 
			
		||||
    isFixedUrlSet(): boolean {
 | 
			
		||||
        if (Array.isArray(CoreConstants.CONFIG.siteurl)) {
 | 
			
		||||
            return CoreConstants.CONFIG.siteurl.length == 1;
 | 
			
		||||
        }
 | 
			
		||||
        return CoreConstants.CONFIG.sites.filter(site => !site.staging).length === 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        return !!CoreConstants.CONFIG.siteurl;
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the app is configured to use a fixed URL (only 1).
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Whether there is 1 fixed URL.
 | 
			
		||||
     */
 | 
			
		||||
    async isSingleFixedSite(): Promise<boolean> {
 | 
			
		||||
        const sites = await this.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
        return sites.length === 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -606,12 +630,9 @@ export class CoreLoginHelperProvider {
 | 
			
		||||
     * @returns Promise resolved with boolean: whether is one of the fixed sites.
 | 
			
		||||
     */
 | 
			
		||||
    async isSiteUrlAllowed(siteUrl: string, checkSiteFinder = true): Promise<boolean> {
 | 
			
		||||
        if (this.isFixedUrlSet()) {
 | 
			
		||||
            // Only 1 site allowed.
 | 
			
		||||
            return CoreUrl.sameDomainAndPath(siteUrl, <string> this.getFixedSites());
 | 
			
		||||
        } else if (this.hasSeveralFixedSites()) {
 | 
			
		||||
            const sites = <CoreLoginSiteInfo[]> this.getFixedSites();
 | 
			
		||||
        const sites = await this.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
        if (sites.length) {
 | 
			
		||||
            return sites.some((site) => CoreUrl.sameDomainAndPath(siteUrl, site.url));
 | 
			
		||||
        } else if (CoreConstants.CONFIG.multisitesdisplay == 'sitefinder' && CoreConstants.CONFIG.onlyallowlistedsites &&
 | 
			
		||||
                checkSiteFinder) {
 | 
			
		||||
@ -1303,12 +1324,14 @@ export class CoreLoginHelperProvider {
 | 
			
		||||
     * @param qrCodeType QR Code type from public config, assuming enabled if undefined.
 | 
			
		||||
     * @returns Whether the QR reader should be displayed in credentials screen.
 | 
			
		||||
     */
 | 
			
		||||
    displayQRInCredentialsScreen(qrCodeType = CoreSiteQRCodeType.QR_CODE_LOGIN): boolean {
 | 
			
		||||
    async displayQRInCredentialsScreen(qrCodeType = CoreSiteQRCodeType.QR_CODE_LOGIN): Promise<boolean> {
 | 
			
		||||
        if (!CoreUtils.canScanQR()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((CoreConstants.CONFIG.displayqroncredentialscreen === undefined && this.isFixedUrlSet()) ||
 | 
			
		||||
        const isSingleFixedSite = await this.isSingleFixedSite();
 | 
			
		||||
 | 
			
		||||
        if ((CoreConstants.CONFIG.displayqroncredentialscreen === undefined && isSingleFixedSite) ||
 | 
			
		||||
            (CoreConstants.CONFIG.displayqroncredentialscreen !== undefined &&
 | 
			
		||||
                !!CoreConstants.CONFIG.displayqroncredentialscreen)) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,17 +18,26 @@ import { CoreLoginError } from '@classes/errors/loginerror';
 | 
			
		||||
import { CoreLoginComponentsModule } from '@features/login/components/components.module';
 | 
			
		||||
import { CoreLoginCredentialsPage } from '@features/login/pages/credentials/credentials';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { Http } from '@singletons';
 | 
			
		||||
import { of } from 'rxjs';
 | 
			
		||||
import { CoreLoginHelper } from '../services/login-helper';
 | 
			
		||||
 | 
			
		||||
describe('Credentials page', () => {
 | 
			
		||||
 | 
			
		||||
    const siteUrl = 'https://campus.example.edu';
 | 
			
		||||
 | 
			
		||||
    beforeEach(() => {
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
        mockSingleton(Http, { get: () => of(null as any) });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('renders', async () => {
 | 
			
		||||
        // Arrange.
 | 
			
		||||
        const siteUrl = 'https://campus.example.edu';
 | 
			
		||||
 | 
			
		||||
        mockSingleton(CoreSites, {
 | 
			
		||||
            getPublicSiteConfigByUrl: async () => ({
 | 
			
		||||
                wwwroot: 'https://campus.example.edu',
 | 
			
		||||
                httpswwwroot: 'https://campus.example.edu',
 | 
			
		||||
                wwwroot: siteUrl,
 | 
			
		||||
                httpswwwroot: siteUrl,
 | 
			
		||||
                sitename: 'Example Campus',
 | 
			
		||||
                guestlogin: 0,
 | 
			
		||||
                rememberusername: 0,
 | 
			
		||||
@ -45,6 +54,8 @@ describe('Credentials page', () => {
 | 
			
		||||
            }),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        mockSingleton(CoreLoginHelper, { getAvailableSites: async () => [{ url: siteUrl, name: 'Example Campus' }] });
 | 
			
		||||
 | 
			
		||||
        // Act.
 | 
			
		||||
        const fixture = await renderPageComponent(CoreLoginCredentialsPage, {
 | 
			
		||||
            routeParams: { siteUrl },
 | 
			
		||||
@ -58,7 +69,7 @@ describe('Credentials page', () => {
 | 
			
		||||
        expect(findElement(fixture, '.core-siteurl', siteUrl)).not.toBeNull();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('suggests contacting support after multiple failed attempts', async () => {
 | 
			
		||||
    it('suggests contacting support after multiple failed attempts', async (done) => {
 | 
			
		||||
        // Arrange.
 | 
			
		||||
        mockSingleton(CoreSites, {
 | 
			
		||||
            getUserToken: () => {
 | 
			
		||||
@ -69,17 +80,15 @@ describe('Credentials page', () => {
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        mockSingleton(CoreLoginHelper, { getAvailableSites: async () => [] });
 | 
			
		||||
 | 
			
		||||
        const fixture = await renderPageComponent(CoreLoginCredentialsPage, {
 | 
			
		||||
            routeParams: {
 | 
			
		||||
                siteUrl: 'https://campus.example.edu',
 | 
			
		||||
                siteConfig: { supportpage: '' },
 | 
			
		||||
            },
 | 
			
		||||
            imports: [
 | 
			
		||||
                CoreSharedModule,
 | 
			
		||||
                CoreLoginComponentsModule,
 | 
			
		||||
            ],
 | 
			
		||||
            routeParams: { siteUrl, siteConfig: { supportpage: '' } },
 | 
			
		||||
            imports: [CoreSharedModule, CoreLoginComponentsModule],
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        done();
 | 
			
		||||
 | 
			
		||||
        // Act.
 | 
			
		||||
        const form = requireElement<HTMLFormElement>(fixture, 'form');
 | 
			
		||||
        const formControls = fixture.componentInstance.credForm.controls;
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
        const currentSite = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
        this.siteId = currentSite.getId();
 | 
			
		||||
        this.siteInfo = currentSite.getInfo();
 | 
			
		||||
        this.siteName = currentSite.getSiteName();
 | 
			
		||||
        this.siteName = await currentSite.getSiteName();
 | 
			
		||||
        this.siteUrl = currentSite.getURL();
 | 
			
		||||
        this.displaySwitchAccount = !currentSite.isFeatureDisabled('NoDelegate_SwitchAccount');
 | 
			
		||||
        this.displayContactSupport = new CoreUserAuthenticatedSupportConfig(currentSite).canContactSupport();
 | 
			
		||||
 | 
			
		||||
@ -45,18 +45,18 @@ export class CoreMainMenuHomePage implements OnInit {
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        this.deepLinkManager = new CoreMainMenuDeepLinkManager();
 | 
			
		||||
 | 
			
		||||
        this.loadSiteName();
 | 
			
		||||
        await this.loadSiteName();
 | 
			
		||||
 | 
			
		||||
        this.subscription = CoreMainMenuHomeDelegate.getHandlersObservable().subscribe((handlers) => {
 | 
			
		||||
            handlers && this.initHandlers(handlers);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Refresh the enabled flags if site is updated.
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
 | 
			
		||||
            this.loadSiteName();
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, async () => {
 | 
			
		||||
            await this.loadSiteName();
 | 
			
		||||
        }, CoreSites.getCurrentSiteId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -99,8 +99,9 @@ export class CoreMainMenuHomePage implements OnInit {
 | 
			
		||||
    /**
 | 
			
		||||
     * Load the site name.
 | 
			
		||||
     */
 | 
			
		||||
    protected loadSiteName(): void {
 | 
			
		||||
        this.siteName = CoreSites.getRequiredCurrentSite().getSiteName() || '';
 | 
			
		||||
    protected async loadSiteName(): Promise<void> {
 | 
			
		||||
        const site = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
        this.siteName = await site.getSiteName() || '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,12 @@
 | 
			
		||||
            </ion-label>
 | 
			
		||||
            <ion-toggle [(ngModel)]="forceSafeAreaMargins" (ionChange)="safeAreaChanged()"></ion-toggle>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
        <ion-item class="ion-text-wrap" *ngIf="stagingSitesCount && enableStagingSites !== undefined">
 | 
			
		||||
            <ion-label>
 | 
			
		||||
                <h2>Enable staging sites ({{stagingSitesCount}})</h2>
 | 
			
		||||
            </ion-label>
 | 
			
		||||
            <ion-toggle [(ngModel)]="enableStagingSites" (ionChange)="setEnabledStagingSites($event.detail.checked)"></ion-toggle>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
        <ng-container *ngIf="siteId">
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
 | 
			
		||||
@ -12,8 +12,10 @@
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { CoreConstants } from '@/core/constants';
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { CoreLoginHelperProvider } from '@features/login/services/login-helper';
 | 
			
		||||
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
 | 
			
		||||
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
 | 
			
		||||
import { CoreUserTours } from '@features/usertours/services/user-tours';
 | 
			
		||||
import { CoreConfig } from '@services/config';
 | 
			
		||||
@ -41,6 +43,9 @@ export class CoreSettingsDevPage implements OnInit {
 | 
			
		||||
    pluginStylesCount = 0;
 | 
			
		||||
    sitePlugins: CoreSitePluginsBasicInfo[] = [];
 | 
			
		||||
    userToursEnabled = true;
 | 
			
		||||
    stagingSitesCount = 0;
 | 
			
		||||
    enableStagingSites?: boolean;
 | 
			
		||||
    listenStagingSitesChanges = false;
 | 
			
		||||
 | 
			
		||||
    disabledFeatures: string[] = [];
 | 
			
		||||
 | 
			
		||||
@ -55,6 +60,13 @@ export class CoreSettingsDevPage implements OnInit {
 | 
			
		||||
 | 
			
		||||
        this.siteId = CoreSites.getCurrentSite()?.getId();
 | 
			
		||||
 | 
			
		||||
        this.stagingSitesCount = CoreConstants.CONFIG.sites.filter((site) => site.staging).length;
 | 
			
		||||
 | 
			
		||||
        if (this.stagingSitesCount) {
 | 
			
		||||
            this.enableStagingSites = await CoreSettingsHelper.hasEnabledStagingSites();
 | 
			
		||||
            this.listenStagingSitesChanges = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.siteId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@ -157,6 +169,22 @@ export class CoreSettingsDevPage implements OnInit {
 | 
			
		||||
        CoreDomUtils.showToast('User tours have been reseted');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async setEnabledStagingSites(enabled: boolean): Promise<void> {
 | 
			
		||||
        if (!this.listenStagingSitesChanges) {
 | 
			
		||||
            this.listenStagingSitesChanges = true;
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreSettingsHelper.setEnabledStagingSites(enabled);
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            this.enableStagingSites = !enabled;
 | 
			
		||||
            this.listenStagingSitesChanges = false;
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Basic site plugin info.
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CorePlatform } from '@services/platform';
 | 
			
		||||
import { CoreNetwork } from '@services/network';
 | 
			
		||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Device Info to be shown and copied to clipboard.
 | 
			
		||||
@ -167,10 +168,6 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const currentSite = sitesProvider.getCurrentSite();
 | 
			
		||||
 | 
			
		||||
        this.deviceInfo.siteUrl = (currentSite?.getURL()) ||
 | 
			
		||||
            (typeof CoreConstants.CONFIG.siteurl == 'string' && CoreConstants.CONFIG.siteurl) || undefined;
 | 
			
		||||
        this.deviceInfo.isPrefixedUrl = !!CoreConstants.CONFIG.siteurl;
 | 
			
		||||
        this.deviceInfo.siteId = currentSite?.getId();
 | 
			
		||||
        this.deviceInfo.siteVersion = currentSite?.getInfo()?.release;
 | 
			
		||||
 | 
			
		||||
@ -189,12 +186,21 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
 | 
			
		||||
     * Async part of the constructor.
 | 
			
		||||
     */
 | 
			
		||||
    protected async asyncInit(): Promise<void> {
 | 
			
		||||
        const sitesProvider = CoreSites.instance;
 | 
			
		||||
        const fileProvider = CoreFile.instance;
 | 
			
		||||
 | 
			
		||||
        const lang = await CoreLang.getCurrentLanguage();
 | 
			
		||||
        this.deviceInfo.currentLanguage = lang;
 | 
			
		||||
        this.currentLangName = CoreConstants.CONFIG.languages[lang];
 | 
			
		||||
 | 
			
		||||
        const currentSite = sitesProvider.getCurrentSite();
 | 
			
		||||
        const isSingleFixedSite = await CoreLoginHelper.isSingleFixedSite();
 | 
			
		||||
        const sites = await CoreLoginHelper.getAvailableSites();
 | 
			
		||||
        const firstUrl = isSingleFixedSite && sites[0].url;
 | 
			
		||||
 | 
			
		||||
        this.deviceInfo.siteUrl = currentSite?.getURL() || firstUrl || undefined;
 | 
			
		||||
        this.deviceInfo.isPrefixedUrl = !!sites.length;
 | 
			
		||||
 | 
			
		||||
        if (fileProvider.isAvailable()) {
 | 
			
		||||
            const basepath = await fileProvider.getBasePath();
 | 
			
		||||
            this.deviceInfo.fileSystemRoot = basepath;
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
            const site = await CoreSites.getSite(siteId);
 | 
			
		||||
            const siteInfo = site.getInfo();
 | 
			
		||||
            siteEntry.siteName = site.getSiteName();
 | 
			
		||||
            siteEntry.siteName = await site.getSiteName();
 | 
			
		||||
 | 
			
		||||
            if (siteInfo) {
 | 
			
		||||
                siteEntry.siteUrl = siteInfo.siteurl;
 | 
			
		||||
 | 
			
		||||
@ -80,7 +80,7 @@ export class CoreSettingsSynchronizationPage implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
            const siteInfo = site.getInfo();
 | 
			
		||||
 | 
			
		||||
            siteEntry.siteName = site.getSiteName();
 | 
			
		||||
            siteEntry.siteName = await site.getSiteName();
 | 
			
		||||
 | 
			
		||||
            if (siteInfo) {
 | 
			
		||||
                siteEntry.siteUrl = siteInfo.siteurl;
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ import { makeSingleton, Translate } from '@singletons';
 | 
			
		||||
import { CoreError } from '@classes/errors/error';
 | 
			
		||||
import { Observable, Subject } from 'rxjs';
 | 
			
		||||
import { CoreTextUtils } from '@services/utils/text';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Object with space usage and cache entries that can be erased.
 | 
			
		||||
@ -477,6 +478,39 @@ export class CoreSettingsHelperProvider {
 | 
			
		||||
        return this.darkModeObservable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get if user enabled staging sites or not.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns Staging sites.
 | 
			
		||||
     */
 | 
			
		||||
    async hasEnabledStagingSites(): Promise<boolean> {
 | 
			
		||||
        const staging = await CoreConfig.get<number>('stagingSites', 0);
 | 
			
		||||
 | 
			
		||||
        return !!staging;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Persist staging sites enabled status and refresh app to apply changes.
 | 
			
		||||
     *
 | 
			
		||||
     * @param enabled Enabled or disabled staging sites.
 | 
			
		||||
     */
 | 
			
		||||
    async setEnabledStagingSites(enabled: boolean): Promise<void> {
 | 
			
		||||
        const reloadApp = !CoreSites.isLoggedIn();
 | 
			
		||||
 | 
			
		||||
        if (reloadApp) {
 | 
			
		||||
            await CoreDomUtils.showConfirm('Are you sure that you want to enable/disable staging sites?');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await CoreConfig.set('stagingSites', enabled ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
        if (!reloadApp) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await CoreNavigator.navigate('/');
 | 
			
		||||
        window.location.reload();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CoreSettingsHelper = makeSingleton(CoreSettingsHelperProvider);
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,7 @@
 | 
			
		||||
import { mock, mockSingleton } from '@/testing/utils';
 | 
			
		||||
import { CoreSite } from '@classes/site';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
 | 
			
		||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
 | 
			
		||||
import { CoreSiteHomeIndexLinkHandlerService } from '@features/sitehome/services/handlers/index-link';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
@ -33,6 +34,8 @@ describe('Site Home link handlers', () => {
 | 
			
		||||
            getSiteIdsFromUrl: () => Promise.resolve([siteId]),
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        mockSingleton(CoreLoginHelper, { getAvailableSites: async () => [{ url: siteUrl, name: 'Example Campus' }] });
 | 
			
		||||
 | 
			
		||||
        CoreContentLinksDelegate.registerHandler(new CoreSiteHomeIndexLinkHandlerService());
 | 
			
		||||
 | 
			
		||||
        // Act.
 | 
			
		||||
 | 
			
		||||
@ -1261,7 +1261,7 @@ export class CoreSitesProvider {
 | 
			
		||||
                    siteUrl: site.siteUrl,
 | 
			
		||||
                    siteUrlWithoutProtocol: site.siteUrl.replace(/^https?:\/\//, '').toLowerCase(),
 | 
			
		||||
                    fullName: siteInfo?.fullname,
 | 
			
		||||
                    siteName: CoreConstants.CONFIG.sitename == '' ? siteInfo?.sitename: CoreConstants.CONFIG.sitename,
 | 
			
		||||
                    siteName: siteInfo?.sitename,
 | 
			
		||||
                    avatar: siteInfo?.userpictureurl,
 | 
			
		||||
                    siteHomeId: siteInfo?.siteid || 1,
 | 
			
		||||
                    loggedOut: !!site.loggedOut,
 | 
			
		||||
@ -2105,6 +2105,16 @@ export type CoreLoginSiteInfo = {
 | 
			
		||||
     * Countrycode of the site.
 | 
			
		||||
     */
 | 
			
		||||
    countrycode?: string;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Is staging site.
 | 
			
		||||
     */
 | 
			
		||||
    staging?: boolean;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Class to apply to site item.
 | 
			
		||||
     */
 | 
			
		||||
    className?: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -109,7 +109,9 @@ export class CoreUpdateManagerProvider {
 | 
			
		||||
     * @returns Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async checkCurrentSiteAllowed(): Promise<void> {
 | 
			
		||||
        if (!CoreLoginHelper.getFixedSites()) {
 | 
			
		||||
        const sites = await CoreLoginHelper.getAvailableSites();
 | 
			
		||||
 | 
			
		||||
        if (!sites.length) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								src/types/config.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								src/types/config.d.ts
									
									
									
									
										vendored
									
									
								
							@ -42,8 +42,7 @@ export interface EnvironmentConfig {
 | 
			
		||||
    zoomlevels: Record<CoreZoomLevel, number>;
 | 
			
		||||
    defaultZoomLevel?: CoreZoomLevel; // Set the default zoom level of the app.
 | 
			
		||||
    customurlscheme: string;
 | 
			
		||||
    siteurl: string | CoreLoginSiteInfo[];
 | 
			
		||||
    sitename: string;
 | 
			
		||||
    sites: CoreLoginSiteInfo[];
 | 
			
		||||
    multisitesdisplay: CoreLoginSiteSelectorListMethod;
 | 
			
		||||
    sitefindersettings: Partial<CoreLoginSiteFinderSettings>;
 | 
			
		||||
    onlyallowlistedsites: boolean;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user