MOBILE-3633 notifications: Implement services
parent
520210a7f6
commit
66e7393603
|
@ -0,0 +1,87 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { CoreSites } from '@services/sites';
|
||||||
|
import { makeSingleton } from '@singletons';
|
||||||
|
import {
|
||||||
|
AddonNotifications,
|
||||||
|
AddonNotificationsAnyNotification,
|
||||||
|
AddonNotificationsGetNotificationsOptions,
|
||||||
|
AddonNotificationsProvider,
|
||||||
|
} from './notifications';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service that provides some helper functions for notifications.
|
||||||
|
*/
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class AddonNotificationsHelperProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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?: AddonNotificationsGetNotificationsOptions,
|
||||||
|
): Promise<{notifications: AddonNotificationsAnyNotification[]; canLoadMore: boolean}> {
|
||||||
|
|
||||||
|
notifications = notifications || [];
|
||||||
|
options = options || {};
|
||||||
|
options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
|
||||||
|
options.siteId = options.siteId || CoreSites.instance.getCurrentSiteId();
|
||||||
|
|
||||||
|
const available = await AddonNotifications.instance.isPopupAvailable(options.siteId);
|
||||||
|
|
||||||
|
if (available) {
|
||||||
|
return AddonNotifications.instance.getPopupNotifications(notifications.length, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to 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.instance.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.instance.getReadNotifications(readFrom, readOptions);
|
||||||
|
|
||||||
|
newNotifications = unread.concat(read);
|
||||||
|
} catch (error) {
|
||||||
|
if (unread.length <= 0) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
notifications: newNotifications,
|
||||||
|
canLoadMore: notifications.length >= options.limit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AddonNotificationsHelper extends makeSingleton(AddonNotificationsHelperProvider) {}
|
|
@ -0,0 +1,658 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { CoreSites, CoreSitesCommonWSOptions } 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';
|
||||||
|
// @todo import { AddonMessages, AddonMessagesMarkMessageReadResult } from '@addon/messages/services/messages';
|
||||||
|
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||||
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import { makeSingleton } from '@singletons';
|
||||||
|
|
||||||
|
const ROOT_CACHE_KEY = 'mmaNotifications:';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service to handle notifications.
|
||||||
|
*/
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class AddonNotificationsProvider {
|
||||||
|
|
||||||
|
static readonly READ_CHANGED_EVENT = 'addon_notifications_read_changed_event';
|
||||||
|
static readonly READ_CRON_EVENT = 'addon_notifications_read_cron_event';
|
||||||
|
static readonly PUSH_SIMULATION_COMPONENT = 'AddonNotificationsPushSimulation';
|
||||||
|
static readonly LIST_LIMIT = 20;
|
||||||
|
|
||||||
|
protected logger: CoreLogger;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.logger = CoreLogger.getInstance('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[]> {
|
||||||
|
|
||||||
|
const promises = notifications.map(async (notificationRaw) => {
|
||||||
|
const notification = <AddonNotificationsAnyNotification> notificationRaw;
|
||||||
|
|
||||||
|
// Set message to show.
|
||||||
|
if (notification.component && notification.component == 'mod_forum') {
|
||||||
|
notification.mobiletext = notification.smallmessage;
|
||||||
|
} else {
|
||||||
|
notification.mobiletext = notification.fullmessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.moodlecomponent = notification.component;
|
||||||
|
notification.notification = 1;
|
||||||
|
notification.notif = 1;
|
||||||
|
if (typeof read != 'undefined') {
|
||||||
|
notification.read = read;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof notification.customdata == 'string') {
|
||||||
|
notification.customdata = CoreTextUtils.instance.parseJSON<Record<string, unknown>>(notification.customdata, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to set courseid the notification belongs to.
|
||||||
|
if (notification.customdata?.courseid) {
|
||||||
|
notification.courseid = <number> notification.customdata.courseid;
|
||||||
|
} else if (!notification.courseid) {
|
||||||
|
const courseIdMatch = notification.fullmessagehtml.match(/course\/view\.php\?id=([^"]*)/);
|
||||||
|
if (courseIdMatch?.[1]) {
|
||||||
|
notification.courseid = parseInt(courseIdMatch[1], 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.useridfrom > 0) {
|
||||||
|
// Try to get the profile picture of the user.
|
||||||
|
try {
|
||||||
|
const user = await CoreUser.instance.getProfile(notification.useridfrom, notification.courseid, true);
|
||||||
|
|
||||||
|
notification.profileimageurlfrom = user.profileimageurl;
|
||||||
|
notification.userfromfullname = user.fullname;
|
||||||
|
} catch {
|
||||||
|
// Error getting user. This can happen if device is offline or the user is deleted.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return notification;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cache key for the get notification preferences call.
|
||||||
|
*
|
||||||
|
* @return Cache key.
|
||||||
|
*/
|
||||||
|
protected getNotificationPreferencesCacheKey(): string {
|
||||||
|
return ROOT_CACHE_KEY + 'notificationPreferences';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get notification preferences.
|
||||||
|
*
|
||||||
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
|
* @return Promise resolved with the notification preferences.
|
||||||
|
*/
|
||||||
|
async getNotificationPreferences(siteId?: string): Promise<AddonNotificationsPreferences> {
|
||||||
|
this.logger.debug('Get notification preferences');
|
||||||
|
|
||||||
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
|
const preSets: CoreSiteWSPreSets = {
|
||||||
|
cacheKey: this.getNotificationPreferencesCacheKey(),
|
||||||
|
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||||
|
};
|
||||||
|
|
||||||
|
const data = await site.read<AddonNotificationsGetUserNotificationPreferencesResult>(
|
||||||
|
'core_message_get_user_notification_preferences',
|
||||||
|
{},
|
||||||
|
preSets,
|
||||||
|
);
|
||||||
|
|
||||||
|
return data.preferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cache key for notification list WS calls.
|
||||||
|
*
|
||||||
|
* @return Cache key.
|
||||||
|
*/
|
||||||
|
protected getNotificationsCacheKey(): string {
|
||||||
|
return ROOT_CACHE_KEY + 'list';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 || {};
|
||||||
|
options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
|
||||||
|
|
||||||
|
this.logger.debug(`Get ${(read ? 'read' : 'unread')} notifications from ${offset}. Limit: ${options.limit}`);
|
||||||
|
|
||||||
|
const site = await CoreSites.instance.getSite(options.siteId);
|
||||||
|
const data: AddonNotificationsGetMessagesWSParams = {
|
||||||
|
useridto: site.getUserId(),
|
||||||
|
useridfrom: 0,
|
||||||
|
type: 'notifications',
|
||||||
|
read: !!read,
|
||||||
|
newestfirst: true,
|
||||||
|
limitfrom: offset,
|
||||||
|
limitnum: options.limit,
|
||||||
|
};
|
||||||
|
const preSets: CoreSiteWSPreSets = {
|
||||||
|
cacheKey: this.getNotificationsCacheKey(),
|
||||||
|
...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get unread notifications.
|
||||||
|
const response = await site.read<AddonNotificationsGetMessagesWSResponse>('core_message_get_messages', data, preSets);
|
||||||
|
|
||||||
|
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.
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
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.instance.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.instance.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unread notifications count. Do not cache calls.
|
||||||
|
*
|
||||||
|
* @param userId The user id who received the notification. If not defined, use current user.
|
||||||
|
* @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> {
|
||||||
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
|
|
||||||
|
// @since 3.2
|
||||||
|
if (site.wsAvailable('message_popup_get_unread_popup_notification_count')) {
|
||||||
|
userId = userId || site.getUserId();
|
||||||
|
const params: AddonNotificationsPopupGetUnreadPopupNotificationCountWSParams = {
|
||||||
|
useridto: userId,
|
||||||
|
};
|
||||||
|
const preSets: CoreSiteWSPreSets = {
|
||||||
|
getFromCache: false,
|
||||||
|
emergencyCache: false,
|
||||||
|
saveToCache: false,
|
||||||
|
typeExpected: 'number',
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await site.read<number>('message_popup_get_unread_popup_notification_count', params, preSets);
|
||||||
|
} catch {
|
||||||
|
// Return no messages if the call fails.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback call
|
||||||
|
try {
|
||||||
|
const unread = await this.getUnreadNotifications(0, { limit: AddonNotificationsProvider.LIST_LIMIT, siteId });
|
||||||
|
|
||||||
|
// The app used to add a + sign if needed, but 3.1 will be dropped soon so it's easier to always return a number.
|
||||||
|
return unread.length;
|
||||||
|
} catch {
|
||||||
|
// Return no messages if the call fails.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not popup WS is available for a certain site.
|
||||||
|
*
|
||||||
|
* @param siteId Site ID. If not defined, current site.
|
||||||
|
* @return Promise resolved with true if available, resolved with false or rejected otherwise.
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
async isPopupAvailable(siteId?: string): Promise<boolean> {
|
||||||
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
|
|
||||||
|
return site.wsAvailable('message_popup_get_popup_notifications');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark all message notification as read.
|
||||||
|
*
|
||||||
|
* @return Resolved when done.
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
async markAllNotificationsAsRead(siteId?: string): Promise<boolean> {
|
||||||
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
|
|
||||||
|
const params: CoreMessageMarkAllNotificationsAsReadWSParams = {
|
||||||
|
useridto: CoreSites.instance.getCurrentSiteUserId(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return site.write<boolean>('core_message_mark_all_notifications_as_read', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a single notification as read.
|
||||||
|
*
|
||||||
|
* @param notificationId ID of notification to mark as read
|
||||||
|
* @param siteId Site ID. If not defined, current site.
|
||||||
|
* @return Promise resolved when done.
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
async markNotificationRead(
|
||||||
|
notificationId: number,
|
||||||
|
siteId?: string,
|
||||||
|
): Promise<CoreMessageMarkNotificationReadWSResponse | undefined> { // @todo | AddonMessagesMarkMessageReadResult
|
||||||
|
|
||||||
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
|
|
||||||
|
if (site.wsAvailable('core_message_mark_notification_read')) {
|
||||||
|
const params: CoreMessageMarkNotificationReadWSParams = {
|
||||||
|
notificationid: notificationId,
|
||||||
|
timeread: CoreTimeUtils.instance.timestamp(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return site.write<CoreMessageMarkNotificationReadWSResponse>('core_message_mark_notification_read', params);
|
||||||
|
} else {
|
||||||
|
// Fallback for versions prior to 3.5.
|
||||||
|
// @todo return AddonMessageProvider.instance.markMessageRead(notificationId, site.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate get notification preferences.
|
||||||
|
*
|
||||||
|
* @param siteId Site ID. If not defined, current site.
|
||||||
|
* @return Promise resolved when data is invalidated.
|
||||||
|
*/
|
||||||
|
async invalidateNotificationPreferences(siteId?: string): Promise<void> {
|
||||||
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
|
|
||||||
|
await site.invalidateWsCacheForKey(this.getNotificationPreferencesCacheKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates notifications list WS calls.
|
||||||
|
*
|
||||||
|
* @param siteId Site ID. If not defined, current site.
|
||||||
|
* @return Promise resolved when the list is invalidated.
|
||||||
|
*/
|
||||||
|
async invalidateNotificationsList(siteId?: string): Promise<void> {
|
||||||
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
|
|
||||||
|
await site.invalidateWsCacheForKey(this.getNotificationsCacheKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not we can mark all notifications as read.
|
||||||
|
*
|
||||||
|
* @return True if enabled, false otherwise.
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
isMarkAllNotificationsAsReadEnabled(): boolean {
|
||||||
|
return CoreSites.instance.wsAvailableInCurrentSite('core_message_mark_all_notifications_as_read');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not we can count unread notifications precisely.
|
||||||
|
*
|
||||||
|
* @return True if enabled, false otherwise.
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
isPreciseNotificationCountEnabled(): boolean {
|
||||||
|
return CoreSites.instance.wsAvailableInCurrentSite('message_popup_get_unread_popup_notification_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the notification preferences are enabled for the current site.
|
||||||
|
*
|
||||||
|
* @return True if enabled, false otherwise.
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
isNotificationPreferencesEnabled(): boolean {
|
||||||
|
return CoreSites.instance.wsAvailableInCurrentSite('core_message_get_user_notification_preferences');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AddonNotifications extends makeSingleton(AddonNotificationsProvider) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preferences returned by core_message_get_user_notification_preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPreferences = {
|
||||||
|
userid: number; // User id.
|
||||||
|
disableall: number | boolean; // Whether all the preferences are disabled.
|
||||||
|
processors: AddonNotificationsPreferencesProcessor[]; // Config form values.
|
||||||
|
components: AddonNotificationsPreferencesComponent[]; // Available components.
|
||||||
|
enableall?: boolean; // Calculated in the app. Whether all the preferences are enabled.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processor in notification preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPreferencesProcessor = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
name: string; // Processor name.
|
||||||
|
hassettings: boolean; // Whether has settings.
|
||||||
|
contextid: number; // Context id.
|
||||||
|
userconfigured: number; // Whether is configured by the user.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component in notification preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPreferencesComponent = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
notifications: AddonNotificationsPreferencesNotification[]; // List of notificaitons for the component.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification processor in notification preferences component.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPreferencesNotification = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
preferencekey: string; // Preference key.
|
||||||
|
processors: AddonNotificationsPreferencesNotificationProcessor[]; // Processors values for this notification.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification processor in notification preferences component.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPreferencesNotificationProcessor = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
name: string; // Processor name.
|
||||||
|
locked: boolean; // Is locked by admin?.
|
||||||
|
lockedmessage?: string; // @since 3.6. Text to display if locked.
|
||||||
|
userconfigured: number; // Is configured?.
|
||||||
|
loggedin: AddonNotificationsPreferencesNotificationProcessorState;
|
||||||
|
loggedoff: AddonNotificationsPreferencesNotificationProcessorState;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State in notification processor in notification preferences component.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPreferencesNotificationProcessorState = {
|
||||||
|
name: string; // Name.
|
||||||
|
displayname: string; // Display name.
|
||||||
|
checked: boolean; // Is checked?.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params of core_message_get_messages WS.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
newestfirst?: boolean; // True for ordering by newest first, false for oldest first.
|
||||||
|
limitfrom?: number; // Limit from.
|
||||||
|
limitnum?: number; // Limit number.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by core_message_get_messages WS.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetMessagesWSResponse = {
|
||||||
|
messages: AddonNotificationsGetMessagesMessage[];
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message data returned by core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetMessagesMessage = {
|
||||||
|
id: number; // Message id.
|
||||||
|
useridfrom: number; // User from id.
|
||||||
|
useridto: number; // User to id.
|
||||||
|
subject: string; // The message subject.
|
||||||
|
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.
|
||||||
|
notification: number; // Is a notification?.
|
||||||
|
contexturl: string; // Context URL.
|
||||||
|
contexturlname: string; // Context URL link name.
|
||||||
|
timecreated: number; // Time created.
|
||||||
|
timeread: number; // Time read.
|
||||||
|
usertofullname: string; // User to full name.
|
||||||
|
userfromfullname: string; // User from full name.
|
||||||
|
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.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_user_notification_preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetUserNotificationPreferencesResult = {
|
||||||
|
preferences: AddonNotificationsPreferences;
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for messages returned by core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationCalculatedData = {
|
||||||
|
mobiletext?: string; // Calculated in the app. Text to display for the notification.
|
||||||
|
moodlecomponent?: string; // Calculated in the app. Moodle's component.
|
||||||
|
notif?: number; // Calculated in the app. Whether it's a notification.
|
||||||
|
notification?: number; // Calculated in the app in some cases. Whether it's a notification.
|
||||||
|
read?: boolean; // Calculated in the app. Whether the notifications is read.
|
||||||
|
courseid?: number; // Calculated in the app. Course the notification belongs to.
|
||||||
|
profileimageurlfrom?: string; // Calculated in the app. Avatar of user that sent the notification.
|
||||||
|
userfromfullname?: string; // Calculated in the app in some cases. User from full name.
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
export type CoreMessageMarkAllNotificationsAsReadWSParams = {
|
||||||
|
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.
|
||||||
|
timecreatedto?: number; // Mark messages created before this time as read, 0 for all messages.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params of core_message_mark_notification_read WS.
|
||||||
|
*/
|
||||||
|
export type CoreMessageMarkNotificationReadWSParams = {
|
||||||
|
notificationid: number; // Id of the notification.
|
||||||
|
timeread?: number; // Timestamp for when the notification should be marked read.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by core_message_mark_notification_read WS.
|
||||||
|
*/
|
||||||
|
export type CoreMessageMarkNotificationReadWSResponse = {
|
||||||
|
notificationid: number; // Id of the notification.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options to pass to getNotifications and getPopupNotifications.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetNotificationsOptions = CoreSitesCommonWSOptions & {
|
||||||
|
limit?: number; // Number of notifications to get. Defaults to LIST_LIMIT.
|
||||||
|
};
|
|
@ -1,9 +1,14 @@
|
||||||
This files describes API changes in the Moodle Mobile app,
|
This files describes API changes in the Moodle Mobile app,
|
||||||
information provided here is intended especially for developers.
|
information provided here is intended especially for developers.
|
||||||
|
|
||||||
|
=== 3.9.5 ===
|
||||||
|
|
||||||
|
- Several functions inside AddonNotificationsProvider have been modified to accept an "options" parameter instead of having several optional parameters.
|
||||||
|
|
||||||
=== 3.9.3 ===
|
=== 3.9.3 ===
|
||||||
|
|
||||||
- In the core-attachments component, passing a -1 as maxSize or maxSubmissions used to mean "unknown limit". Now -1 means unlimited. Also, passing a 0 to maxSize used to mean "unknown" too, now 0 means user max size.
|
- In the core-attachments component, passing a -1 as maxSize or maxSubmissions used to mean "unknown limit". Now -1 means unlimited. Also, passing a 0 to maxSize used to mean "unknown" too, now 0 means user max size.
|
||||||
|
- Most functions that call a WebService in addons/mod have been modified to accept an "options" parameter instead of having several optional parameters.
|
||||||
|
|
||||||
=== 3.8.3 ===
|
=== 3.8.3 ===
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue