commit
28bb27bd65
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p class="item-heading">{{ notification.subject }}</p>
|
<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-label>
|
||||||
<ion-note slot="end" class="ion-float-end ion-text-end">
|
<ion-note slot="end" class="ion-float-end ion-text-end">
|
||||||
{{ notification.timecreated | coreDateDayOrTime }}
|
{{ notification.timecreated | coreDateDayOrTime }}
|
||||||
|
|
|
@ -21,8 +21,11 @@ import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreEvents, CoreEventObserver } from '@singletons/events';
|
import { CoreEvents, CoreEventObserver } from '@singletons/events';
|
||||||
import { AddonNotifications, AddonNotificationsAnyNotification, AddonNotificationsProvider } from '../../services/notifications';
|
import {
|
||||||
import { AddonNotificationsHelper } from '../../services/notifications-helper';
|
AddonNotifications,
|
||||||
|
AddonNotificationsNotificationMessageFormatted,
|
||||||
|
AddonNotificationsProvider,
|
||||||
|
} from '../../services/notifications';
|
||||||
import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate';
|
import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,9 +92,7 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
||||||
this.loadMoreError = false;
|
this.loadMoreError = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await AddonNotificationsHelper.getNotifications(refresh ? [] : this.notifications, {
|
const result = await AddonNotifications.getNotifications(refresh ? [] : this.notifications);
|
||||||
onlyPopupNotifications: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const notifications = result.notifications.map((notification) => this.formatText(notification));
|
const notifications = result.notifications.map((notification) => this.formatText(notification));
|
||||||
|
|
||||||
|
@ -156,9 +157,9 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
||||||
try {
|
try {
|
||||||
this.loadingMarkAllNotificationsAsRead = true;
|
this.loadingMarkAllNotificationsAsRead = true;
|
||||||
|
|
||||||
const unread = await AddonNotifications.getUnreadNotificationsCount();
|
const unreadCountData = await AddonNotifications.getUnreadNotificationsCount();
|
||||||
|
|
||||||
this.canMarkAllNotificationsAsRead = unread > 0;
|
this.canMarkAllNotificationsAsRead = unreadCountData.count > 0;
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingMarkAllNotificationsAsRead = false;
|
this.loadingMarkAllNotificationsAsRead = false;
|
||||||
}
|
}
|
||||||
|
@ -198,14 +199,14 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
||||||
*
|
*
|
||||||
* @param notification The notification object.
|
* @param notification The notification object.
|
||||||
*/
|
*/
|
||||||
protected formatText(notification: AddonNotificationsAnyNotification): FormattedNotification {
|
protected formatText(notification: AddonNotificationsNotificationMessageFormatted): FormattedNotification {
|
||||||
const formattedNotification: FormattedNotification = notification;
|
const formattedNotification: FormattedNotification = notification;
|
||||||
formattedNotification.displayfullhtml = this.shouldDisplayFullHtml(notification);
|
formattedNotification.displayfullhtml = this.shouldDisplayFullHtml(notification);
|
||||||
formattedNotification.iconurl = formattedNotification.iconurl || undefined; // Make sure the property exists.
|
formattedNotification.iconurl = formattedNotification.iconurl || undefined; // Make sure the property exists.
|
||||||
|
|
||||||
formattedNotification.mobiletext = formattedNotification.displayfullhtml ?
|
formattedNotification.mobiletext = formattedNotification.displayfullhtml ?
|
||||||
notification.fullmessagehtml :
|
notification.fullmessagehtml :
|
||||||
CoreTextUtils.replaceNewLines(formattedNotification.mobiletext!.replace(/-{4,}/ig, ''), '<br>');
|
CoreTextUtils.replaceNewLines((formattedNotification.mobiletext || '').replace(/-{4,}/ig, ''), '<br>');
|
||||||
|
|
||||||
return formattedNotification;
|
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.
|
displayfullhtml?: boolean; // Whether to display the full HTML of the notification.
|
||||||
iconurl?: string;
|
iconurl?: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="preferences">
|
<ion-item class="ion-text-wrap" *ngIf="preferences">
|
||||||
<ion-label>{{ 'addon.notifications.notifications' | translate }}</ion-label>
|
<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>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="canChangeSound">
|
<ion-item class="ion-text-wrap" *ngIf="canChangeSound">
|
||||||
<ion-label>{{ 'addon.notifications.playsound' | translate }}</ion-label>
|
<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.
|
* @param name Name of the selected processor.
|
||||||
*/
|
*/
|
||||||
changeProcessor(name: string): void {
|
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) {
|
if (processor) {
|
||||||
this.loadProcessor(processor);
|
this.loadProcessor(processor);
|
||||||
|
@ -246,6 +246,10 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
async enableAll(enable?: boolean): Promise<void> {
|
async enableAll(enable?: boolean): Promise<void> {
|
||||||
|
if (!this.preferences) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -256,7 +260,7 @@ export class AddonNotificationsSettingsPage implements OnInit, OnDestroy {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Show error and revert change.
|
// Show error and revert change.
|
||||||
CoreDomUtils.showErrorModal(error);
|
CoreDomUtils.showErrorModal(error);
|
||||||
this.preferences!.enableall = !this.preferences!.enableall;
|
this.preferences.enableall = !this.preferences.enableall;
|
||||||
} finally {
|
} finally {
|
||||||
modal.dismiss();
|
modal.dismiss();
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,10 +110,12 @@ export class AddonNotificationsMainMenuHandlerService implements CoreMainMenuHan
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const unreadCount = await AddonNotifications.getUnreadNotificationsCount(undefined, siteId);
|
const unreadCountData = await AddonNotifications.getUnreadNotificationsCount(undefined, siteId);
|
||||||
|
|
||||||
this.handlerData.badge = unreadCount > 0 ? String(unreadCount) : '';
|
this.handlerData.badge = unreadCountData.count > 0 ?
|
||||||
CorePushNotifications.updateAddonCounter('AddonNotifications', unreadCount, siteId);
|
unreadCountData.count + (unreadCountData.hasMore ? '+' : '') :
|
||||||
|
'';
|
||||||
|
CorePushNotifications.updateAddonCounter('AddonNotifications', unreadCountData.count, siteId);
|
||||||
} catch {
|
} catch {
|
||||||
this.handlerData.badge = '';
|
this.handlerData.badge = '';
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -14,20 +14,15 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { CoreSites } from '@services/sites';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate';
|
import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate';
|
||||||
import {
|
import {
|
||||||
AddonNotifications,
|
|
||||||
AddonNotificationsAnyNotification,
|
|
||||||
AddonNotificationsGetNotificationsOptions,
|
|
||||||
AddonNotificationsPreferences,
|
AddonNotificationsPreferences,
|
||||||
AddonNotificationsPreferencesComponent,
|
AddonNotificationsPreferencesComponent,
|
||||||
AddonNotificationsPreferencesNotification,
|
AddonNotificationsPreferencesNotification,
|
||||||
AddonNotificationsPreferencesNotificationProcessor,
|
AddonNotificationsPreferencesNotificationProcessor,
|
||||||
AddonNotificationsPreferencesProcessor,
|
AddonNotificationsPreferencesProcessor,
|
||||||
AddonNotificationsProvider,
|
|
||||||
} from './notifications';
|
} from './notifications';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,57 +53,6 @@ export class AddonNotificationsHelperProvider {
|
||||||
return formattedPreferences;
|
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.
|
* Get a certain processor from a list of processors.
|
||||||
*
|
*
|
||||||
|
@ -207,10 +151,3 @@ export type AddonNotificationsPreferencesNotificationFormatted = AddonNotificati
|
||||||
export type AddonNotificationsPreferencesProcessorFormatted = AddonNotificationsPreferencesProcessor & {
|
export type AddonNotificationsPreferencesProcessorFormatted = AddonNotificationsPreferencesProcessor & {
|
||||||
supported?: boolean; // Calculated in the app. Whether the processor is supported in the app.
|
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 { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
|
||||||
|
|
||||||
const ROOT_CACHE_KEY = 'mmaNotifications:';
|
const ROOT_CACHE_KEY = 'mmaNotifications:';
|
||||||
|
|
||||||
|
@ -46,24 +47,14 @@ export class AddonNotificationsProvider {
|
||||||
* Function to format notification data.
|
* Function to format notification data.
|
||||||
*
|
*
|
||||||
* @param notifications List of notifications.
|
* @param notifications List of notifications.
|
||||||
* @param read Whether the notifications are read or unread.
|
|
||||||
* @return Promise resolved with notifications.
|
* @return Promise resolved with notifications.
|
||||||
*/
|
*/
|
||||||
protected async formatNotificationsData(
|
protected async formatNotificationsData(
|
||||||
notifications: AddonNotificationsGetMessagesMessage[],
|
notifications: AddonNotificationsNotificationMessage[],
|
||||||
read?: boolean,
|
): Promise<AddonNotificationsNotificationMessageFormatted[]> {
|
||||||
): Promise<AddonNotificationsGetMessagesMessageFormatted[]>;
|
|
||||||
protected async formatNotificationsData(
|
|
||||||
notifications: AddonNotificationsPopupNotification[],
|
|
||||||
read?: boolean,
|
|
||||||
): Promise<AddonNotificationsPopupNotificationFormatted[]>;
|
|
||||||
protected async formatNotificationsData(
|
|
||||||
notifications: (AddonNotificationsGetMessagesMessage | AddonNotificationsPopupNotification)[],
|
|
||||||
read?: boolean,
|
|
||||||
): Promise<AddonNotificationsAnyNotification[]> {
|
|
||||||
|
|
||||||
const promises = notifications.map(async (notificationRaw) => {
|
const promises = notifications.map(async (notificationRaw) => {
|
||||||
const notification = <AddonNotificationsAnyNotification> notificationRaw;
|
const notification = <AddonNotificationsNotificationMessageFormatted> notificationRaw;
|
||||||
|
|
||||||
// Set message to show.
|
// Set message to show.
|
||||||
if (notification.component && notification.component == 'mod_forum') {
|
if (notification.component && notification.component == 'mod_forum') {
|
||||||
|
@ -75,9 +66,7 @@ export class AddonNotificationsProvider {
|
||||||
notification.moodlecomponent = notification.component;
|
notification.moodlecomponent = notification.component;
|
||||||
notification.notification = 1;
|
notification.notification = 1;
|
||||||
notification.notif = 1;
|
notification.notif = 1;
|
||||||
if (typeof read != 'undefined') {
|
notification.read = notification.timeread > 0;
|
||||||
notification.read = read;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof notification.customdata == 'string') {
|
if (typeof notification.customdata == 'string') {
|
||||||
notification.customdata = CoreTextUtils.parseJSON<Record<string, unknown>>(notification.customdata, {});
|
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) {
|
if (notification.useridfrom > 0) {
|
||||||
// Try to get the profile picture of the user.
|
// Try to get the profile picture of the user.
|
||||||
try {
|
try {
|
||||||
|
@ -153,32 +151,99 @@ export class AddonNotificationsProvider {
|
||||||
return ROOT_CACHE_KEY + 'list';
|
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.
|
* Get notifications from site.
|
||||||
*
|
*
|
||||||
* @param read True if should get read notifications, false otherwise.
|
* @param read True if should get read notifications, false otherwise.
|
||||||
* @param offset Position of the first notification to get.
|
|
||||||
* @param options Other options.
|
* @param options Other options.
|
||||||
* @return Promise resolved with notifications.
|
* @return Promise resolved with notifications.
|
||||||
*/
|
*/
|
||||||
async getNotifications(
|
protected async getNotificationsWithStatus(
|
||||||
read: boolean,
|
read: AddonNotificationsGetReadType,
|
||||||
offset: number,
|
options: AddonNotificationsGetNotificationsOptions = {},
|
||||||
options?: AddonNotificationsGetNotificationsOptions,
|
): Promise<AddonNotificationsNotificationMessageFormatted[]> {
|
||||||
): Promise<AddonNotificationsGetMessagesMessageFormatted[]> {
|
options.offset = options.offset || 0;
|
||||||
options = options || {};
|
|
||||||
options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
|
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 site = await CoreSites.getSite(options.siteId);
|
||||||
|
|
||||||
const data: AddonNotificationsGetMessagesWSParams = {
|
const data: AddonNotificationsGetMessagesWSParams = {
|
||||||
useridto: site.getUserId(),
|
useridto: site.getUserId(),
|
||||||
useridfrom: 0,
|
useridfrom: 0,
|
||||||
type: 'notifications',
|
type: 'notifications',
|
||||||
read: !!read,
|
read: read,
|
||||||
newestfirst: true,
|
newestfirst: true,
|
||||||
limitfrom: offset,
|
limitfrom: options.offset,
|
||||||
limitnum: options.limit,
|
limitnum: options.limit,
|
||||||
};
|
};
|
||||||
const preSets: CoreSiteWSPreSets = {
|
const preSets: CoreSiteWSPreSets = {
|
||||||
|
@ -191,78 +256,7 @@ export class AddonNotificationsProvider {
|
||||||
|
|
||||||
const notifications = response.messages;
|
const notifications = response.messages;
|
||||||
|
|
||||||
return this.formatNotificationsData(notifications, read);
|
return this.formatNotificationsData(notifications);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -272,28 +266,67 @@ export class AddonNotificationsProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved with the message notifications count.
|
* @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);
|
const site = await CoreSites.getSite(siteId);
|
||||||
|
|
||||||
userId = userId || site.getUserId();
|
// @since 4.0
|
||||||
const params: AddonNotificationsPopupGetUnreadPopupNotificationCountWSParams = {
|
if (site.wsAvailable('core_message_get_unread_notification_count')) {
|
||||||
useridto: userId,
|
const params: CoreMessageGetUnreadNotificationCountWSParams = {
|
||||||
|
useridto: userId || site.getUserId(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const preSets: CoreSiteWSPreSets = {
|
const preSets: CoreSiteWSPreSets = {
|
||||||
getFromCache: false,
|
cacheKey: this.getUnreadNotificationsCountCacheKey(params.useridto),
|
||||||
emergencyCache: false,
|
getFromCache: false, // Always try to get the latest number.
|
||||||
saveToCache: false,
|
|
||||||
typeExpected: 'number',
|
typeExpected: 'number',
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
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 {
|
} catch {
|
||||||
// Return no messages if the call fails.
|
// Return no notifications if the call fails.
|
||||||
return 0;
|
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.
|
* 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.
|
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.
|
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.
|
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.
|
newestfirst?: boolean; // True for ordering by newest first, false for oldest first.
|
||||||
limitfrom?: number; // Limit from.
|
limitfrom?: number; // Limit from.
|
||||||
limitnum?: number; // Limit number.
|
limitnum?: number; // Limit number.
|
||||||
|
@ -437,14 +470,14 @@ export type AddonNotificationsGetMessagesWSParams = {
|
||||||
* Data returned by core_message_get_messages WS.
|
* Data returned by core_message_get_messages WS.
|
||||||
*/
|
*/
|
||||||
export type AddonNotificationsGetMessagesWSResponse = {
|
export type AddonNotificationsGetMessagesWSResponse = {
|
||||||
messages: AddonNotificationsGetMessagesMessage[];
|
messages: AddonNotificationsNotificationMessage[];
|
||||||
warnings?: CoreWSExternalWarning[];
|
warnings?: CoreWSExternalWarning[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message data returned by core_message_get_messages.
|
* Message data returned by core_message_get_messages.
|
||||||
*/
|
*/
|
||||||
export type AddonNotificationsGetMessagesMessage = {
|
export type AddonNotificationsNotificationMessage = {
|
||||||
id: number; // Message id.
|
id: number; // Message id.
|
||||||
useridfrom: number; // User from id.
|
useridfrom: number; // User from id.
|
||||||
useridto: number; // User to id.
|
useridto: number; // User to id.
|
||||||
|
@ -464,70 +497,14 @@ export type AddonNotificationsGetMessagesMessage = {
|
||||||
component?: string; // @since 3.7. The component that generated the notification.
|
component?: string; // @since 3.7. The component that generated the notification.
|
||||||
eventtype?: string; // @since 3.7. The type of notification.
|
eventtype?: string; // @since 3.7. The type of notification.
|
||||||
customdata?: string; // @since 3.7. Custom data to be passed to the message processor.
|
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.
|
* Message data returned by core_message_get_messages with some calculated data.
|
||||||
*/
|
*/
|
||||||
export type AddonNotificationsGetMessagesMessageFormatted =
|
export type AddonNotificationsNotificationMessageFormatted =
|
||||||
Omit<AddonNotificationsGetMessagesMessage, 'customdata'> & AddonNotificationsNotificationCalculatedData;
|
Omit<AddonNotificationsNotificationMessage, '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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result of WS core_message_get_user_notification_preferences.
|
* Result of WS core_message_get_user_notification_preferences.
|
||||||
|
@ -552,13 +529,6 @@ export type AddonNotificationsNotificationCalculatedData = {
|
||||||
customdata?: Record<string, unknown>; // Parsed custom data.
|
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.
|
* 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 & {
|
export type AddonNotificationsGetNotificationsOptions = CoreSitesCommonWSOptions & {
|
||||||
|
offset?: number; // Offset to use. Defaults to 0.
|
||||||
limit?: number; // Number of notifications to get. Defaults to LIST_LIMIT.
|
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.9': 2020061500,
|
||||||
'3.10': 2020110900,
|
'3.10': 2020110900,
|
||||||
'3.11': 2021051700,
|
'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.
|
// Possible cache update frequencies.
|
||||||
|
|
Loading…
Reference in New Issue