commit
						28bb27bd65
					
				@ -36,7 +36,7 @@
 | 
			
		||||
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <p class="item-heading">{{ notification.subject }}</p>
 | 
			
		||||
                    <p *ngIf="notification.userfromfullname">{{ notification.userfromfullname }}</p>
 | 
			
		||||
                    <p *ngIf="notification.useridfrom > 0">{{ notification.userfromfullname }}</p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
                <ion-note slot="end" class="ion-float-end ion-text-end">
 | 
			
		||||
                    {{ notification.timecreated | coreDateDayOrTime }}
 | 
			
		||||
 | 
			
		||||
@ -21,8 +21,11 @@ import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreTextUtils } from '@services/utils/text';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreEvents, CoreEventObserver } from '@singletons/events';
 | 
			
		||||
import { AddonNotifications, AddonNotificationsAnyNotification, AddonNotificationsProvider } from '../../services/notifications';
 | 
			
		||||
import { AddonNotificationsHelper } from '../../services/notifications-helper';
 | 
			
		||||
import {
 | 
			
		||||
    AddonNotifications,
 | 
			
		||||
    AddonNotificationsNotificationMessageFormatted,
 | 
			
		||||
    AddonNotificationsProvider,
 | 
			
		||||
} from '../../services/notifications';
 | 
			
		||||
import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -89,9 +92,7 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
 | 
			
		||||
        this.loadMoreError = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const result = await AddonNotificationsHelper.getNotifications(refresh ? [] : this.notifications, {
 | 
			
		||||
                onlyPopupNotifications: true,
 | 
			
		||||
            });
 | 
			
		||||
            const result = await AddonNotifications.getNotifications(refresh ? [] : this.notifications);
 | 
			
		||||
 | 
			
		||||
            const notifications = result.notifications.map((notification) => this.formatText(notification));
 | 
			
		||||
 | 
			
		||||
@ -156,9 +157,9 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
 | 
			
		||||
        try {
 | 
			
		||||
            this.loadingMarkAllNotificationsAsRead = true;
 | 
			
		||||
 | 
			
		||||
            const unread = await AddonNotifications.getUnreadNotificationsCount();
 | 
			
		||||
            const unreadCountData = await AddonNotifications.getUnreadNotificationsCount();
 | 
			
		||||
 | 
			
		||||
            this.canMarkAllNotificationsAsRead = unread > 0;
 | 
			
		||||
            this.canMarkAllNotificationsAsRead = unreadCountData.count > 0;
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.loadingMarkAllNotificationsAsRead = false;
 | 
			
		||||
        }
 | 
			
		||||
@ -198,14 +199,14 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification The notification object.
 | 
			
		||||
     */
 | 
			
		||||
    protected formatText(notification: AddonNotificationsAnyNotification): FormattedNotification {
 | 
			
		||||
    protected formatText(notification: AddonNotificationsNotificationMessageFormatted): FormattedNotification {
 | 
			
		||||
        const formattedNotification: FormattedNotification = notification;
 | 
			
		||||
        formattedNotification.displayfullhtml = this.shouldDisplayFullHtml(notification);
 | 
			
		||||
        formattedNotification.iconurl = formattedNotification.iconurl || undefined; // Make sure the property exists.
 | 
			
		||||
 | 
			
		||||
        formattedNotification.mobiletext = formattedNotification.displayfullhtml ?
 | 
			
		||||
            notification.fullmessagehtml :
 | 
			
		||||
            CoreTextUtils.replaceNewLines(formattedNotification.mobiletext!.replace(/-{4,}/ig, ''), '<br>');
 | 
			
		||||
            CoreTextUtils.replaceNewLines((formattedNotification.mobiletext || '').replace(/-{4,}/ig, ''), '<br>');
 | 
			
		||||
 | 
			
		||||
        return formattedNotification;
 | 
			
		||||
    }
 | 
			
		||||
@ -253,7 +254,7 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FormattedNotification = AddonNotificationsAnyNotification & {
 | 
			
		||||
type FormattedNotification = AddonNotificationsNotificationMessageFormatted & {
 | 
			
		||||
    displayfullhtml?: boolean; // Whether to display the full HTML of the notification.
 | 
			
		||||
    iconurl?: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@
 | 
			
		||||
        <ion-card>
 | 
			
		||||
            <ion-item class="ion-text-wrap" *ngIf="preferences">
 | 
			
		||||
                <ion-label>{{ 'addon.notifications.notifications' | translate }}</ion-label>
 | 
			
		||||
                <ion-toggle [(ngModel)]="preferences!.enableall" (ngModelChange)="enableAll(preferences!.enableall)"></ion-toggle>
 | 
			
		||||
                <ion-toggle [(ngModel)]="preferences.enableall" (ngModelChange)="enableAll(preferences.enableall)"></ion-toggle>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
            <ion-item class="ion-text-wrap" *ngIf="canChangeSound">
 | 
			
		||||
                <ion-label>{{ 'addon.notifications.playsound' | translate }}</ion-label>
 | 
			
		||||
 | 
			
		||||
@ -161,7 +161,7 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
 | 
			
		||||
     * @param name Name of the selected processor.
 | 
			
		||||
     */
 | 
			
		||||
    changeProcessor(name: string): void {
 | 
			
		||||
        const processor = this.preferences!.processors.find((processor) => processor.name == name);
 | 
			
		||||
        const processor = this.preferences?.processors.find((processor) => processor.name == name);
 | 
			
		||||
 | 
			
		||||
        if (processor) {
 | 
			
		||||
            this.loadProcessor(processor);
 | 
			
		||||
@ -246,6 +246,10 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async enableAll(enable?: boolean): Promise<void> {
 | 
			
		||||
        if (!this.preferences) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const modal = await CoreDomUtils.showModalLoading('core.sending', true);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
@ -256,7 +260,7 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            // Show error and revert change.
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
            this.preferences!.enableall = !this.preferences!.enableall;
 | 
			
		||||
            this.preferences.enableall = !this.preferences.enableall;
 | 
			
		||||
        } finally {
 | 
			
		||||
            modal.dismiss();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -110,10 +110,12 @@ export class AddonNotificationsMainMenuHandlerService implements CoreMainMenuHan
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const unreadCount = await AddonNotifications.getUnreadNotificationsCount(undefined, siteId);
 | 
			
		||||
            const unreadCountData = await AddonNotifications.getUnreadNotificationsCount(undefined, siteId);
 | 
			
		||||
 | 
			
		||||
            this.handlerData.badge = unreadCount > 0 ? String(unreadCount) : '';
 | 
			
		||||
            CorePushNotifications.updateAddonCounter('AddonNotifications', unreadCount, siteId);
 | 
			
		||||
            this.handlerData.badge = unreadCountData.count > 0 ?
 | 
			
		||||
                unreadCountData.count + (unreadCountData.hasMore ? '+' : '') :
 | 
			
		||||
                '';
 | 
			
		||||
            CorePushNotifications.updateAddonCounter('AddonNotifications', unreadCountData.count, siteId);
 | 
			
		||||
        } catch {
 | 
			
		||||
            this.handlerData.badge = '';
 | 
			
		||||
        } finally {
 | 
			
		||||
 | 
			
		||||
@ -14,20 +14,15 @@
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    AddonNotifications,
 | 
			
		||||
    AddonNotificationsAnyNotification,
 | 
			
		||||
    AddonNotificationsGetNotificationsOptions,
 | 
			
		||||
    AddonNotificationsPreferences,
 | 
			
		||||
    AddonNotificationsPreferencesComponent,
 | 
			
		||||
    AddonNotificationsPreferencesNotification,
 | 
			
		||||
    AddonNotificationsPreferencesNotificationProcessor,
 | 
			
		||||
    AddonNotificationsPreferencesProcessor,
 | 
			
		||||
    AddonNotificationsProvider,
 | 
			
		||||
} from './notifications';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -58,57 +53,6 @@ export class AddonNotificationsHelperProvider {
 | 
			
		||||
        return formattedPreferences;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get some notifications. It will try to use the new WS if available.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notifications Current list of loaded notifications. It's used to calculate the offset.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved with notifications and if can load more.
 | 
			
		||||
     */
 | 
			
		||||
    async getNotifications(
 | 
			
		||||
        notifications: AddonNotificationsAnyNotification[],
 | 
			
		||||
        options?: AddonNotificationsHelperGetNotificationsOptions,
 | 
			
		||||
    ): Promise<{notifications: AddonNotificationsAnyNotification[]; canLoadMore: boolean}> {
 | 
			
		||||
 | 
			
		||||
        notifications = notifications || [];
 | 
			
		||||
        options = options || {};
 | 
			
		||||
        options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
 | 
			
		||||
        options.siteId = options.siteId || CoreSites.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        if (options.onlyPopupNotifications) {
 | 
			
		||||
            return AddonNotifications.getPopupNotifications(notifications.length, options);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Use get_messages. We need 2 calls, one for read and the other one for unread.
 | 
			
		||||
        const unreadFrom = notifications.reduce((total, current) => total + (current.read ? 0 : 1), 0);
 | 
			
		||||
 | 
			
		||||
        const unread = await AddonNotifications.getUnreadNotifications(unreadFrom, options);
 | 
			
		||||
 | 
			
		||||
        let newNotifications = unread;
 | 
			
		||||
 | 
			
		||||
        if (unread.length < options.limit) {
 | 
			
		||||
            // Limit not reached. Get read notifications until reach the limit.
 | 
			
		||||
            const readLimit = options.limit - unread.length;
 | 
			
		||||
            const readFrom = notifications.length - unreadFrom;
 | 
			
		||||
            const readOptions = Object.assign({}, options, { limit: readLimit });
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                const read = await AddonNotifications.getReadNotifications(readFrom, readOptions);
 | 
			
		||||
 | 
			
		||||
                newNotifications = unread.concat(read);
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                if (unread.length <= 0) {
 | 
			
		||||
                    throw error;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            notifications: newNotifications,
 | 
			
		||||
            canLoadMore: notifications.length >= options.limit,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a certain processor from a list of processors.
 | 
			
		||||
     *
 | 
			
		||||
@ -207,10 +151,3 @@ export type AddonNotificationsPreferencesNotificationFormatted = AddonNotificati
 | 
			
		||||
export type AddonNotificationsPreferencesProcessorFormatted = AddonNotificationsPreferencesProcessor & {
 | 
			
		||||
    supported?: boolean; // Calculated in the app. Whether the processor is supported in the app.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Options to pass to getNotifications.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsHelperGetNotificationsOptions = AddonNotificationsGetNotificationsOptions & {
 | 
			
		||||
    onlyPopupNotifications?: boolean; // Whether to get only popup notifications.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,7 @@ import { CoreUser } from '@features/user/services/user';
 | 
			
		||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
 | 
			
		||||
import { CoreLogger } from '@singletons/logger';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
 | 
			
		||||
 | 
			
		||||
const ROOT_CACHE_KEY = 'mmaNotifications:';
 | 
			
		||||
 | 
			
		||||
@ -46,24 +47,14 @@ export class AddonNotificationsProvider {
 | 
			
		||||
     * Function to format notification data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notifications List of notifications.
 | 
			
		||||
     * @param read Whether the notifications are read or unread.
 | 
			
		||||
     * @return Promise resolved with notifications.
 | 
			
		||||
     */
 | 
			
		||||
    protected async formatNotificationsData(
 | 
			
		||||
        notifications: AddonNotificationsGetMessagesMessage[],
 | 
			
		||||
        read?: boolean,
 | 
			
		||||
    ): Promise<AddonNotificationsGetMessagesMessageFormatted[]>;
 | 
			
		||||
    protected async formatNotificationsData(
 | 
			
		||||
        notifications: AddonNotificationsPopupNotification[],
 | 
			
		||||
        read?: boolean,
 | 
			
		||||
    ): Promise<AddonNotificationsPopupNotificationFormatted[]>;
 | 
			
		||||
    protected async formatNotificationsData(
 | 
			
		||||
        notifications: (AddonNotificationsGetMessagesMessage | AddonNotificationsPopupNotification)[],
 | 
			
		||||
        read?: boolean,
 | 
			
		||||
    ): Promise<AddonNotificationsAnyNotification[]> {
 | 
			
		||||
        notifications: AddonNotificationsNotificationMessage[],
 | 
			
		||||
    ): Promise<AddonNotificationsNotificationMessageFormatted[]> {
 | 
			
		||||
 | 
			
		||||
        const promises = notifications.map(async (notificationRaw) => {
 | 
			
		||||
            const notification = <AddonNotificationsAnyNotification> notificationRaw;
 | 
			
		||||
            const notification = <AddonNotificationsNotificationMessageFormatted> notificationRaw;
 | 
			
		||||
 | 
			
		||||
            // Set message to show.
 | 
			
		||||
            if (notification.component && notification.component == 'mod_forum') {
 | 
			
		||||
@ -75,9 +66,7 @@ export class AddonNotificationsProvider {
 | 
			
		||||
            notification.moodlecomponent = notification.component;
 | 
			
		||||
            notification.notification = 1;
 | 
			
		||||
            notification.notif = 1;
 | 
			
		||||
            if (typeof read != 'undefined') {
 | 
			
		||||
                notification.read = read;
 | 
			
		||||
            }
 | 
			
		||||
            notification.read = notification.timeread > 0;
 | 
			
		||||
 | 
			
		||||
            if (typeof notification.customdata == 'string') {
 | 
			
		||||
                notification.customdata = CoreTextUtils.parseJSON<Record<string, unknown>>(notification.customdata, {});
 | 
			
		||||
@ -93,6 +82,15 @@ export class AddonNotificationsProvider {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!notification.iconurl) {
 | 
			
		||||
                // The iconurl is only returned in 4.0 or above. Calculate it if not present.
 | 
			
		||||
                if (notification.component && notification.component.startsWith('mod_')) {
 | 
			
		||||
                    notification.iconurl = await CoreCourseModuleDelegate.getModuleIconSrc(
 | 
			
		||||
                        notification.component.replace('mod_', ''),
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (notification.useridfrom > 0) {
 | 
			
		||||
                // Try to get the profile picture of the user.
 | 
			
		||||
                try {
 | 
			
		||||
@ -153,32 +151,99 @@ export class AddonNotificationsProvider {
 | 
			
		||||
        return ROOT_CACHE_KEY + 'list';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get some notifications.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notifications Current list of loaded notifications. It's used to calculate the offset.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved with notifications and if can load more.
 | 
			
		||||
     */
 | 
			
		||||
    async getNotifications(
 | 
			
		||||
        notifications: AddonNotificationsNotificationMessageFormatted[],
 | 
			
		||||
        options?: AddonNotificationsGetNotificationsOptions,
 | 
			
		||||
    ): Promise<{notifications: AddonNotificationsNotificationMessageFormatted[]; canLoadMore: boolean}> {
 | 
			
		||||
 | 
			
		||||
        notifications = notifications || [];
 | 
			
		||||
        options = options || {};
 | 
			
		||||
        options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
 | 
			
		||||
        options.siteId = options.siteId || CoreSites.getCurrentSiteId();
 | 
			
		||||
        let newNotifications: AddonNotificationsNotificationMessageFormatted[];
 | 
			
		||||
 | 
			
		||||
        // Request 1 more notification so we can know if there are more notifications.
 | 
			
		||||
        const originalLimit = options.limit;
 | 
			
		||||
        options.limit + 1;
 | 
			
		||||
 | 
			
		||||
        const site = await CoreSites.getSite(options.siteId);
 | 
			
		||||
 | 
			
		||||
        if (site.isVersionGreaterEqualThan('4.0')) {
 | 
			
		||||
            // In 4.0 the app can request read and unread at the same time.
 | 
			
		||||
            options.offset = notifications.length;
 | 
			
		||||
            newNotifications = await this.getNotificationsWithStatus(
 | 
			
		||||
                AddonNotificationsGetReadType.BOTH,
 | 
			
		||||
                options,
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // We need 2 calls, one for read and the other one for unread.
 | 
			
		||||
            options.offset = notifications.reduce((total, current) => total + (current.read ? 0 : 1), 0);
 | 
			
		||||
 | 
			
		||||
            const unread = await this.getNotificationsWithStatus(AddonNotificationsGetReadType.UNREAD, options);
 | 
			
		||||
 | 
			
		||||
            newNotifications = unread;
 | 
			
		||||
 | 
			
		||||
            if (unread.length < options.limit) {
 | 
			
		||||
                // Limit not reached. Get read notifications until reach the limit.
 | 
			
		||||
                const readOptions = {
 | 
			
		||||
                    ...options,
 | 
			
		||||
                    offset: notifications.length - options.offset,
 | 
			
		||||
                    limit: options.limit - unread.length,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                try {
 | 
			
		||||
                    const read = await this.getNotificationsWithStatus(AddonNotificationsGetReadType.READ, readOptions);
 | 
			
		||||
 | 
			
		||||
                    newNotifications = unread.concat(read);
 | 
			
		||||
                } catch (error) {
 | 
			
		||||
                    if (unread.length <= 0) {
 | 
			
		||||
                        throw error;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            notifications: newNotifications.slice(0, originalLimit),
 | 
			
		||||
            canLoadMore: newNotifications.length > originalLimit,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get notifications from site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param read True if should get read notifications, false otherwise.
 | 
			
		||||
     * @param offset Position of the first notification to get.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved with notifications.
 | 
			
		||||
     */
 | 
			
		||||
    async getNotifications(
 | 
			
		||||
        read: boolean,
 | 
			
		||||
        offset: number,
 | 
			
		||||
        options?: AddonNotificationsGetNotificationsOptions,
 | 
			
		||||
    ): Promise<AddonNotificationsGetMessagesMessageFormatted[]> {
 | 
			
		||||
        options = options || {};
 | 
			
		||||
    protected async getNotificationsWithStatus(
 | 
			
		||||
        read: AddonNotificationsGetReadType,
 | 
			
		||||
        options: AddonNotificationsGetNotificationsOptions = {},
 | 
			
		||||
    ): Promise<AddonNotificationsNotificationMessageFormatted[]> {
 | 
			
		||||
        options.offset = options.offset || 0;
 | 
			
		||||
        options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
 | 
			
		||||
 | 
			
		||||
        this.logger.debug(`Get ${(read ? 'read' : 'unread')} notifications from ${offset}. Limit: ${options.limit}`);
 | 
			
		||||
        const typeText = read === AddonNotificationsGetReadType.READ ?
 | 
			
		||||
            'read' :
 | 
			
		||||
            (read === AddonNotificationsGetReadType.UNREAD ? 'unread' : 'read and unread');
 | 
			
		||||
        this.logger.debug(`Get ${typeText} notifications from ${options.offset}. Limit: ${options.limit}`);
 | 
			
		||||
 | 
			
		||||
        const site = await CoreSites.getSite(options.siteId);
 | 
			
		||||
 | 
			
		||||
        const data: AddonNotificationsGetMessagesWSParams = {
 | 
			
		||||
            useridto: site.getUserId(),
 | 
			
		||||
            useridfrom: 0,
 | 
			
		||||
            type: 'notifications',
 | 
			
		||||
            read: !!read,
 | 
			
		||||
            read: read,
 | 
			
		||||
            newestfirst: true,
 | 
			
		||||
            limitfrom: offset,
 | 
			
		||||
            limitfrom: options.offset,
 | 
			
		||||
            limitnum: options.limit,
 | 
			
		||||
        };
 | 
			
		||||
        const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
@ -191,78 +256,7 @@ export class AddonNotificationsProvider {
 | 
			
		||||
 | 
			
		||||
        const notifications = response.messages;
 | 
			
		||||
 | 
			
		||||
        return this.formatNotificationsData(notifications, read);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get notifications from site using the new WebService.
 | 
			
		||||
     *
 | 
			
		||||
     * @param offset Position of the first notification to get.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved with notifications and if can load more.
 | 
			
		||||
     */
 | 
			
		||||
    async getPopupNotifications(
 | 
			
		||||
        offset: number,
 | 
			
		||||
        options?: AddonNotificationsGetNotificationsOptions,
 | 
			
		||||
    ): Promise<{notifications: AddonNotificationsPopupNotificationFormatted[]; canLoadMore: boolean}> {
 | 
			
		||||
        options = options || {};
 | 
			
		||||
        options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
 | 
			
		||||
 | 
			
		||||
        this.logger.debug(`Get popup notifications from ${offset}. Limit: ${options.limit}`);
 | 
			
		||||
 | 
			
		||||
        const site = await CoreSites.getSite(options.siteId);
 | 
			
		||||
        const data: AddonNotificationsPopupGetPopupNotificationsWSParams = {
 | 
			
		||||
            useridto: site.getUserId(),
 | 
			
		||||
            newestfirst: true,
 | 
			
		||||
            offset,
 | 
			
		||||
            limit: options.limit + 1, // Get one more to calculate canLoadMore.
 | 
			
		||||
        };
 | 
			
		||||
        const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
            cacheKey: this.getNotificationsCacheKey(),
 | 
			
		||||
            ...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Get notifications.
 | 
			
		||||
        const response = await site.read<AddonNotificationsGetPopupNotificationsResult>(
 | 
			
		||||
            'message_popup_get_popup_notifications',
 | 
			
		||||
            data,
 | 
			
		||||
            preSets,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const notifications = await this.formatNotificationsData(response.notifications.slice(0, options.limit));
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            canLoadMore: response.notifications.length > options.limit,
 | 
			
		||||
            notifications,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get read notifications from site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param offset Position of the first notification to get.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved with notifications.
 | 
			
		||||
     */
 | 
			
		||||
    getReadNotifications(
 | 
			
		||||
        offset: number,
 | 
			
		||||
        options?: AddonNotificationsGetNotificationsOptions,
 | 
			
		||||
    ): Promise<AddonNotificationsGetMessagesMessageFormatted[]> {
 | 
			
		||||
        return this.getNotifications(true, offset, options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get unread notifications from site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param offset Position of the first notification to get.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved with notifications.
 | 
			
		||||
     */
 | 
			
		||||
    getUnreadNotifications(
 | 
			
		||||
        offset: number,
 | 
			
		||||
        options?: AddonNotificationsGetNotificationsOptions,
 | 
			
		||||
    ): Promise<AddonNotificationsGetMessagesMessageFormatted[]> {
 | 
			
		||||
        return this.getNotifications(false, offset, options);
 | 
			
		||||
        return this.formatNotificationsData(notifications);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -272,28 +266,67 @@ export class AddonNotificationsProvider {
 | 
			
		||||
     * @param siteId Site ID. If not defined, use current site.
 | 
			
		||||
     * @return Promise resolved with the message notifications count.
 | 
			
		||||
     */
 | 
			
		||||
    async getUnreadNotificationsCount(userId?: number, siteId?: string): Promise<number> {
 | 
			
		||||
    async getUnreadNotificationsCount(userId?: number, siteId?: string): Promise<{ count: number; hasMore: boolean} > {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        userId = userId || site.getUserId();
 | 
			
		||||
        const params: AddonNotificationsPopupGetUnreadPopupNotificationCountWSParams = {
 | 
			
		||||
            useridto: userId,
 | 
			
		||||
        // @since 4.0
 | 
			
		||||
        if (site.wsAvailable('core_message_get_unread_notification_count')) {
 | 
			
		||||
            const params: CoreMessageGetUnreadNotificationCountWSParams = {
 | 
			
		||||
                useridto: userId || site.getUserId(),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
            getFromCache: false,
 | 
			
		||||
            emergencyCache: false,
 | 
			
		||||
            saveToCache: false,
 | 
			
		||||
                cacheKey: this.getUnreadNotificationsCountCacheKey(params.useridto),
 | 
			
		||||
                getFromCache: false, // Always try to get the latest number.
 | 
			
		||||
                typeExpected: 'number',
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
            return await site.read<number>('message_popup_get_unread_popup_notification_count', params, preSets);
 | 
			
		||||
                const count = await site.read<number>('core_message_get_unread_notification_count', params, preSets);
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    count,
 | 
			
		||||
                    hasMore: false,
 | 
			
		||||
                };
 | 
			
		||||
            } catch {
 | 
			
		||||
            // Return no messages if the call fails.
 | 
			
		||||
            return 0;
 | 
			
		||||
                // Return no notifications if the call fails.
 | 
			
		||||
                return {
 | 
			
		||||
                    count: 0,
 | 
			
		||||
                    hasMore: false,
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fallback call
 | 
			
		||||
        try {
 | 
			
		||||
            const unread = await this.getNotificationsWithStatus(AddonNotificationsGetReadType.UNREAD, {
 | 
			
		||||
                limit: AddonNotificationsProvider.LIST_LIMIT + 1,
 | 
			
		||||
                siteId,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                count: Math.min(unread.length, AddonNotificationsProvider.LIST_LIMIT),
 | 
			
		||||
                hasMore: unread.length > AddonNotificationsProvider.LIST_LIMIT,
 | 
			
		||||
            };
 | 
			
		||||
        } catch {
 | 
			
		||||
            // Return no notifications if the call fails.
 | 
			
		||||
            return {
 | 
			
		||||
                count: 0,
 | 
			
		||||
                hasMore: false,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for unread notifications count WS calls.
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId User ID.
 | 
			
		||||
     * @return Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getUnreadNotificationsCountCacheKey(userId: number): string {
 | 
			
		||||
        return `${ROOT_CACHE_KEY}count:${userId}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Mark all message notification as read.
 | 
			
		||||
     *
 | 
			
		||||
@ -427,7 +460,7 @@ export type AddonNotificationsGetMessagesWSParams = {
 | 
			
		||||
    useridto: number; // The user id who received the message, 0 for any user.
 | 
			
		||||
    useridfrom?: number; // The user id who send the message, 0 for any user. -10 or -20 for no-reply or support user.
 | 
			
		||||
    type?: string; // Type of message to return, expected values are: notifications, conversations and both.
 | 
			
		||||
    read?: boolean; // True for getting read messages, false for unread.
 | 
			
		||||
    read?: AddonNotificationsGetReadType; // 0=unread, 1=read. @since 4.0 it also accepts 2=both.
 | 
			
		||||
    newestfirst?: boolean; // True for ordering by newest first, false for oldest first.
 | 
			
		||||
    limitfrom?: number; // Limit from.
 | 
			
		||||
    limitnum?: number; // Limit number.
 | 
			
		||||
@ -437,14 +470,14 @@ export type AddonNotificationsGetMessagesWSParams = {
 | 
			
		||||
 * Data returned by core_message_get_messages WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsGetMessagesWSResponse = {
 | 
			
		||||
    messages: AddonNotificationsGetMessagesMessage[];
 | 
			
		||||
    messages: AddonNotificationsNotificationMessage[];
 | 
			
		||||
    warnings?: CoreWSExternalWarning[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Message data returned by core_message_get_messages.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsGetMessagesMessage = {
 | 
			
		||||
export type AddonNotificationsNotificationMessage = {
 | 
			
		||||
    id: number; // Message id.
 | 
			
		||||
    useridfrom: number; // User from id.
 | 
			
		||||
    useridto: number; // User to id.
 | 
			
		||||
@ -464,70 +497,14 @@ export type AddonNotificationsGetMessagesMessage = {
 | 
			
		||||
    component?: string; // @since 3.7. The component that generated the notification.
 | 
			
		||||
    eventtype?: string; // @since 3.7. The type of notification.
 | 
			
		||||
    customdata?: string; // @since 3.7. Custom data to be passed to the message processor.
 | 
			
		||||
    iconurl?: string; // @since 4.0. Icon URL, only for notifications.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Message data returned by core_message_get_messages with some calculated data.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsGetMessagesMessageFormatted =
 | 
			
		||||
        Omit<AddonNotificationsGetMessagesMessage, 'customdata'> & AddonNotificationsNotificationCalculatedData;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of message_popup_get_popup_notifications WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsPopupGetPopupNotificationsWSParams = {
 | 
			
		||||
    useridto: number; // The user id who received the message, 0 for current user.
 | 
			
		||||
    newestfirst?: boolean; // True for ordering by newest first, false for oldest first.
 | 
			
		||||
    limit?: number; // The number of results to return.
 | 
			
		||||
    offset?: number; // Offset the result set by a given amount.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Result of WS message_popup_get_popup_notifications.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsGetPopupNotificationsResult = {
 | 
			
		||||
    notifications: AddonNotificationsPopupNotification[];
 | 
			
		||||
    unreadcount: number; // The number of unread message for the given user.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Notification returned by message_popup_get_popup_notifications.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsPopupNotification = {
 | 
			
		||||
    id: number; // Notification id (this is not guaranteed to be unique within this result set).
 | 
			
		||||
    useridfrom: number; // User from id.
 | 
			
		||||
    useridto: number; // User to id.
 | 
			
		||||
    subject: string; // The notification subject.
 | 
			
		||||
    shortenedsubject: string; // The notification subject shortened with ellipsis.
 | 
			
		||||
    text: string; // The message text formated.
 | 
			
		||||
    fullmessage: string; // The message.
 | 
			
		||||
    fullmessageformat: number; // Fullmessage format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
 | 
			
		||||
    fullmessagehtml: string; // The message in html.
 | 
			
		||||
    smallmessage: string; // The shorten message.
 | 
			
		||||
    contexturl: string; // Context URL.
 | 
			
		||||
    contexturlname: string; // Context URL link name.
 | 
			
		||||
    timecreated: number; // Time created.
 | 
			
		||||
    timecreatedpretty: string; // Time created in a pretty format.
 | 
			
		||||
    timeread: number; // Time read.
 | 
			
		||||
    read: boolean; // Notification read status.
 | 
			
		||||
    deleted: boolean; // Notification deletion status.
 | 
			
		||||
    iconurl: string; // URL for notification icon.
 | 
			
		||||
    component?: string; // The component that generated the notification.
 | 
			
		||||
    eventtype?: string; // The type of notification.
 | 
			
		||||
    customdata?: string; // @since 3.7. Custom data to be passed to the message processor.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Notification returned by message_popup_get_popup_notifications.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsPopupNotificationFormatted =
 | 
			
		||||
        Omit<AddonNotificationsPopupNotification, 'customdata'> & AddonNotificationsNotificationCalculatedData;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Any kind of notification that can be retrieved.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsAnyNotification =
 | 
			
		||||
        AddonNotificationsPopupNotificationFormatted | AddonNotificationsGetMessagesMessageFormatted;
 | 
			
		||||
export type AddonNotificationsNotificationMessageFormatted =
 | 
			
		||||
        Omit<AddonNotificationsNotificationMessage, 'customdata'> & AddonNotificationsNotificationCalculatedData;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Result of WS core_message_get_user_notification_preferences.
 | 
			
		||||
@ -552,13 +529,6 @@ export type AddonNotificationsNotificationCalculatedData = {
 | 
			
		||||
    customdata?: Record<string, unknown>; // Parsed custom data.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of message_popup_get_unread_popup_notification_count WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsPopupGetUnreadPopupNotificationCountWSParams = {
 | 
			
		||||
    useridto: number; // The user id who received the message, 0 for any user.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of core_message_mark_all_notifications_as_read WS.
 | 
			
		||||
 */
 | 
			
		||||
@ -585,8 +555,25 @@ export type CoreMessageMarkNotificationReadWSResponse = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Options to pass to getNotifications and getPopupNotifications.
 | 
			
		||||
 * Params of core_message_get_unread_notification_count WS.
 | 
			
		||||
 */
 | 
			
		||||
export type CoreMessageGetUnreadNotificationCountWSParams = {
 | 
			
		||||
    useridto: number; // User id who received the notification, 0 for any user.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Options to pass to getNotifications.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonNotificationsGetNotificationsOptions = CoreSitesCommonWSOptions & {
 | 
			
		||||
    offset?: number; // Offset to use. Defaults to 0.
 | 
			
		||||
    limit?: number; // Number of notifications to get. Defaults to LIST_LIMIT.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Constants to get either read, unread or both notifications.
 | 
			
		||||
 */
 | 
			
		||||
export enum AddonNotificationsGetReadType {
 | 
			
		||||
    UNREAD = 0,
 | 
			
		||||
    READ = 1,
 | 
			
		||||
    BOTH = 2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -86,6 +86,7 @@ export class CoreSite {
 | 
			
		||||
        '3.9': 2020061500,
 | 
			
		||||
        '3.10': 2020110900,
 | 
			
		||||
        '3.11': 2021051700,
 | 
			
		||||
        '4.0': 2021100300, // @todo [4.0] replace with right value when released. Using a tmp value to be able to test new things.
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Possible cache update frequencies.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user