forked from CIT/Vmeda.Online
		
	MOBILE-3902 notifications: Warn admin if push are disabled
This commit is contained in:
		
							parent
							
								
									d60b954a81
								
							
						
					
					
						commit
						7c5a7050e9
					
				@ -1063,6 +1063,7 @@
 | 
			
		||||
  "addon.notifications.notificationpreferences": "message",
 | 
			
		||||
  "addon.notifications.notifications": "local_moodlemobileapp",
 | 
			
		||||
  "addon.notifications.playsound": "local_moodlemobileapp",
 | 
			
		||||
  "addon.notifications.pushdisabledwarning": "local_moodlemobileapp",
 | 
			
		||||
  "addon.notifications.therearentnotificationsyet": "local_moodlemobileapp",
 | 
			
		||||
  "addon.notifications.unreadnotification": "message",
 | 
			
		||||
  "addon.privatefiles.couldnotloadfiles": "local_moodlemobileapp",
 | 
			
		||||
@ -1667,6 +1668,7 @@
 | 
			
		||||
  "core.fulllistofcourses": "moodle",
 | 
			
		||||
  "core.fullnameandsitename": "local_moodlemobileapp",
 | 
			
		||||
  "core.fullscreen": "h5p",
 | 
			
		||||
  "core.goto": "local_moodlemobileapp",
 | 
			
		||||
  "core.grades.aggregatemean": "grades",
 | 
			
		||||
  "core.grades.aggregatesum": "grades",
 | 
			
		||||
  "core.grades.average": "grades",
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
    "notificationpreferences": "Notification preferences",
 | 
			
		||||
    "notifications": "Notifications",
 | 
			
		||||
    "playsound": "Play sound",
 | 
			
		||||
    "pushdisabledwarning": "Your users are not receiving any notification from this site on their mobile devices. Enable mobile notifications in the Notification settings page.",
 | 
			
		||||
    "therearentnotificationsyet": "There are no notifications.",
 | 
			
		||||
    "unreadnotification": "Unread notification: {{$a}}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ import { AddonNotificationsCronHandler } from './services/handlers/cron';
 | 
			
		||||
import { AddonNotificationsPushClickHandler } from './services/handlers/push-click';
 | 
			
		||||
import { AddonNotificationsSettingsHandler, AddonNotificationsSettingsHandlerService } from './services/handlers/settings';
 | 
			
		||||
import { CoreSitePreferencesRoutingModule } from '@features/settings/pages/site/site-routing';
 | 
			
		||||
import { AddonNotificationsProvider } from './services/notifications';
 | 
			
		||||
import { AddonNotifications, AddonNotificationsProvider } from './services/notifications';
 | 
			
		||||
import { AddonNotificationsHelperProvider } from './services/notifications-helper';
 | 
			
		||||
 | 
			
		||||
export const ADDON_NOTIFICATIONS_SERVICES: Type<unknown>[] = [
 | 
			
		||||
@ -65,6 +65,7 @@ const preferencesRoutes: Routes = [
 | 
			
		||||
                CoreSettingsDelegate.registerHandler(AddonNotificationsSettingsHandler.instance);
 | 
			
		||||
 | 
			
		||||
                AddonNotificationsMainMenuHandler.initialize();
 | 
			
		||||
                AddonNotifications.initialize();
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
@ -14,15 +14,18 @@
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
			
		||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
 | 
			
		||||
import { CoreWSExternalWarning } from '@services/ws';
 | 
			
		||||
import { CoreTextUtils } from '@services/utils/text';
 | 
			
		||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
			
		||||
import { CoreUser } from '@features/user/services/user';
 | 
			
		||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
 | 
			
		||||
import { CoreLogger } from '@singletons/logger';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { makeSingleton, Translate } from '@singletons';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
 | 
			
		||||
import { CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
 | 
			
		||||
const ROOT_CACHE_KEY = 'mmaNotifications:';
 | 
			
		||||
 | 
			
		||||
@ -43,6 +46,15 @@ export class AddonNotificationsProvider {
 | 
			
		||||
        this.logger = CoreLogger.getInstance('AddonNotificationsProvider');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the service.
 | 
			
		||||
     */
 | 
			
		||||
    initialize(): void {
 | 
			
		||||
        CoreEvents.on(CoreEvents.LOGIN, (data) => {
 | 
			
		||||
            this.warnPushDisabledForAdmin(data.siteId);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Function to format notification data.
 | 
			
		||||
     *
 | 
			
		||||
@ -115,16 +127,17 @@ export class AddonNotificationsProvider {
 | 
			
		||||
    /**
 | 
			
		||||
     * Get notification preferences.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID. If not defined, use current site.
 | 
			
		||||
     * @param options Options.
 | 
			
		||||
     * @return Promise resolved with the notification preferences.
 | 
			
		||||
     */
 | 
			
		||||
    async getNotificationPreferences(siteId?: string): Promise<AddonNotificationsPreferences> {
 | 
			
		||||
    async getNotificationPreferences(options: CoreSitesCommonWSOptions = {}): Promise<AddonNotificationsPreferences> {
 | 
			
		||||
        this.logger.debug('Get notification preferences');
 | 
			
		||||
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
        const site = await CoreSites.getSite(options.siteId);
 | 
			
		||||
        const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
            cacheKey: this.getNotificationPreferencesCacheKey(),
 | 
			
		||||
            updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
 | 
			
		||||
            ...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const data = await site.read<AddonNotificationsGetUserNotificationPreferencesResult>(
 | 
			
		||||
@ -382,6 +395,80 @@ export class AddonNotificationsProvider {
 | 
			
		||||
        await site.invalidateWsCacheForKey(this.getNotificationsCacheKey());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Is user is an admin and push are disabled, notify him.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async warnPushDisabledForAdmin(siteId?: string): Promise<void> {
 | 
			
		||||
        if (!siteId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
            if (!site.getInfo()?.userissiteadmin) {
 | 
			
		||||
                // Not an admin or we don't know, stop.
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Check if the admin already asked not to be reminded.
 | 
			
		||||
            const dontAsk = await site.getLocalSiteConfig('AddonNotificationsDontRemindPushDisabled', 0);
 | 
			
		||||
            if (dontAsk) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Check if push are disabled.
 | 
			
		||||
            const preferences = await this.getNotificationPreferences({
 | 
			
		||||
                readingStrategy: CoreSitesReadingStrategy.ONLY_NETWORK,
 | 
			
		||||
                siteId,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const processor = preferences.processors.find(processor => processor.name === 'airnotifier');
 | 
			
		||||
            if (processor) {
 | 
			
		||||
                // Enabled.
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Warn the admin.
 | 
			
		||||
            const dontShowAgain = await CoreDomUtils.showPrompt(
 | 
			
		||||
                Translate.instant('addon.notifications.pushdisabledwarning'),
 | 
			
		||||
                undefined,
 | 
			
		||||
                Translate.instant('core.dontshowagain'),
 | 
			
		||||
                'checkbox',
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        text: Translate.instant('core.ok'),
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        text: Translate.instant('core.goto', { $a: Translate.instant('core.settings.settings') }),
 | 
			
		||||
                        handler: (data, resolve) => {
 | 
			
		||||
                            resolve(data[0]);
 | 
			
		||||
 | 
			
		||||
                            const url = CoreTextUtils.concatenatePaths(
 | 
			
		||||
                                site.getURL(),
 | 
			
		||||
                                site.isVersionGreaterEqualThan('3.11') ?
 | 
			
		||||
                                    'message/output/airnotifier/checkconfiguration.php' :
 | 
			
		||||
                                    'admin/message.php',
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            // Don't try auto-login, admins cannot use it.
 | 
			
		||||
                            CoreUtils.openInBrowser(url);
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            if (dontShowAgain) {
 | 
			
		||||
                await site.setLocalSiteConfig('AddonNotificationsDontRemindPushDisabled', 1);
 | 
			
		||||
            }
 | 
			
		||||
        } catch {
 | 
			
		||||
            // Ignore errors.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const AddonNotifications = makeSingleton(AddonNotificationsProvider);
 | 
			
		||||
 | 
			
		||||
@ -123,6 +123,7 @@
 | 
			
		||||
    "fulllistofcourses": "All courses",
 | 
			
		||||
    "fullnameandsitename": "{{fullname}} ({{sitename}})",
 | 
			
		||||
    "fullscreen": "Fullscreen",
 | 
			
		||||
    "goto": "Go to {{$a}}",
 | 
			
		||||
    "group": "Group",
 | 
			
		||||
    "groupsseparate": "Separate groups",
 | 
			
		||||
    "groupsvisible": "Visible groups",
 | 
			
		||||
 | 
			
		||||
@ -1478,7 +1478,7 @@ export class CoreDomUtilsProvider {
 | 
			
		||||
     * @param header Modal header.
 | 
			
		||||
     * @param placeholderOrLabel Placeholder (for textual/numeric inputs) or label (for radio/checkbox). By default, "Password".
 | 
			
		||||
     * @param type Type of the input element. By default, password.
 | 
			
		||||
     * @param options More options to pass to the alert.
 | 
			
		||||
     * @param buttons Buttons. If not provided, OK and Cancel buttons will be displayed.
 | 
			
		||||
     * @return Promise resolved with the input data (true for checkbox/radio) if the user clicks OK, rejected if cancels.
 | 
			
		||||
     */
 | 
			
		||||
    showPrompt(
 | 
			
		||||
@ -1486,12 +1486,25 @@ export class CoreDomUtilsProvider {
 | 
			
		||||
        header?: string,
 | 
			
		||||
        placeholderOrLabel?: string,
 | 
			
		||||
        type: TextFieldTypes | 'checkbox' | 'radio' | 'textarea' = 'password',
 | 
			
		||||
        buttons?: PromptButton[],
 | 
			
		||||
    ): Promise<any> { // eslint-disable-line @typescript-eslint/no-explicit-any
 | 
			
		||||
        return new Promise((resolve, reject) => {
 | 
			
		||||
            placeholderOrLabel = placeholderOrLabel ?? Translate.instant('core.login.password');
 | 
			
		||||
 | 
			
		||||
            const isCheckbox = type === 'checkbox';
 | 
			
		||||
            const isRadio = type === 'radio';
 | 
			
		||||
 | 
			
		||||
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
            const resolvePromise = (data: any) => {
 | 
			
		||||
                if (isCheckbox) {
 | 
			
		||||
                    resolve(data[0]);
 | 
			
		||||
                } else if (isRadio) {
 | 
			
		||||
                    resolve(data);
 | 
			
		||||
                } else {
 | 
			
		||||
                    resolve(data.promptinput);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const options: AlertOptions = {
 | 
			
		||||
                header,
 | 
			
		||||
                message,
 | 
			
		||||
@ -1504,7 +1517,25 @@ export class CoreDomUtilsProvider {
 | 
			
		||||
                        value: (isCheckbox || isRadio) ? true : undefined,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                buttons: [
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if (buttons?.length) {
 | 
			
		||||
                options.buttons = buttons.map((button) => ({
 | 
			
		||||
                    ...button,
 | 
			
		||||
                    handler: (data) => {
 | 
			
		||||
                        if (!button.handler) {
 | 
			
		||||
                            // Just resolve the promise.
 | 
			
		||||
                            resolvePromise(data);
 | 
			
		||||
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        button.handler(data, resolve, reject);
 | 
			
		||||
                    },
 | 
			
		||||
                }));
 | 
			
		||||
            } else {
 | 
			
		||||
                // Default buttons.
 | 
			
		||||
                options.buttons = [
 | 
			
		||||
                    {
 | 
			
		||||
                        text: Translate.instant('core.cancel'),
 | 
			
		||||
                        role: 'cancel',
 | 
			
		||||
@ -1514,18 +1545,10 @@ export class CoreDomUtilsProvider {
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        text: Translate.instant('core.ok'),
 | 
			
		||||
                        handler: (data) => {
 | 
			
		||||
                            if (isCheckbox) {
 | 
			
		||||
                                resolve(data[0]);
 | 
			
		||||
                            } else if (isRadio) {
 | 
			
		||||
                                resolve(data);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                resolve(data.promptinput);
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        handler: resolvePromise,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            };
 | 
			
		||||
                ];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.showAlertWithOptions(options);
 | 
			
		||||
        });
 | 
			
		||||
@ -2045,3 +2068,11 @@ export type OpenModalOptions = ModalOptions & {
 | 
			
		||||
    waitForDismissCompleted?: boolean;
 | 
			
		||||
    closeOnNavigate?: boolean; // Default true.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Buttons for prompt alert.
 | 
			
		||||
 */
 | 
			
		||||
export type PromptButton = Omit<AlertButton, 'handler'> & {
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
    handler?: (value: any, resolve: (value: any) => void, reject: (reason: any) => void) => void;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user