From 7c42b886b1c07e05eedc64a60ce6dcac9d6145dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 22 Feb 2018 12:12:48 +0100 Subject: [PATCH] MOBILE-2327 messages: Add messages handlers --- src/addon/messages/messages.module.ts | 31 ++++++- .../providers/discussion-link-handler.ts | 89 +++++++++++++++++++ .../messages/providers/index-link-handler.ts | 66 ++++++++++++++ .../messages/providers/sync-cron-handler.ts | 48 ++++++++++ src/addon/messages/providers/sync.ts | 6 +- .../providers/user-send-message-handler.ts | 77 ++++++++++++++++ src/classes/base-sync.ts | 6 +- src/providers/config.ts | 4 +- src/providers/cron.ts | 10 +-- 9 files changed, 321 insertions(+), 16 deletions(-) create mode 100644 src/addon/messages/providers/discussion-link-handler.ts create mode 100644 src/addon/messages/providers/index-link-handler.ts create mode 100644 src/addon/messages/providers/sync-cron-handler.ts create mode 100644 src/addon/messages/providers/user-send-message-handler.ts diff --git a/src/addon/messages/messages.module.ts b/src/addon/messages/messages.module.ts index 6edcabe59..ad9499a94 100644 --- a/src/addon/messages/messages.module.ts +++ b/src/addon/messages/messages.module.ts @@ -13,12 +13,20 @@ // limitations under the License. import { NgModule } from '@angular/core'; +import { Network } from '@ionic-native/network'; import { AddonMessagesProvider } from './providers/messages'; import { AddonMessagesOfflineProvider } from './providers/messages-offline'; import { AddonMessagesSyncProvider } from './providers/sync'; import { AddonMessagesMainMenuHandler } from './providers/mainmenu-handler'; - import { CoreMainMenuDelegate } from '../../core/mainmenu/providers/delegate'; +import { CoreContentLinksDelegate } from '../../core/contentlinks/providers/delegate'; +import { CoreUserDelegate } from '../../core/user/providers/user-delegate'; +import { CoreCronDelegate } from '../../providers/cron'; +import { AddonMessagesSendMessageUserHandler } from './providers/user-send-message-handler'; +import { AddonMessagesDiscussionLinkHandler } from './providers/discussion-link-handler'; +import { AddonMessagesIndexLinkHandler } from './providers/index-link-handler'; +import { AddonMessagesSyncCronHandler } from './providers/sync-cron-handler'; +import { CoreEventsProvider } from '../../providers/events'; @NgModule({ declarations: [ @@ -29,12 +37,29 @@ import { CoreMainMenuDelegate } from '../../core/mainmenu/providers/delegate'; AddonMessagesProvider, AddonMessagesOfflineProvider, AddonMessagesSyncProvider, - AddonMessagesMainMenuHandler + AddonMessagesMainMenuHandler, + AddonMessagesSendMessageUserHandler, + AddonMessagesDiscussionLinkHandler, + AddonMessagesIndexLinkHandler, + AddonMessagesSyncCronHandler ] }) export class AddonMessagesModule { - constructor(mainMenuDelegate: CoreMainMenuDelegate, mainmenuHandler: AddonMessagesMainMenuHandler) { + constructor(mainMenuDelegate: CoreMainMenuDelegate, mainmenuHandler: AddonMessagesMainMenuHandler, + contentLinksDelegate: CoreContentLinksDelegate, indexLinkHandler: AddonMessagesIndexLinkHandler, + discussionLinkHandler: AddonMessagesDiscussionLinkHandler, sendMessageHandler: AddonMessagesSendMessageUserHandler, + userDelegate: CoreUserDelegate, cronDelegate: CoreCronDelegate, syncHandler: AddonMessagesSyncCronHandler, + network: Network, messagesSync: AddonMessagesSyncProvider) { // Register handlers. mainMenuDelegate.registerHandler(mainmenuHandler); + contentLinksDelegate.registerHandler(indexLinkHandler); + contentLinksDelegate.registerHandler(discussionLinkHandler); + userDelegate.registerHandler(sendMessageHandler); + cronDelegate.register(syncHandler); + + // Sync some discussions when device goes online. + network.onConnect().subscribe(() => { + messagesSync.syncAllDiscussions(undefined, true); + }); } } diff --git a/src/addon/messages/providers/discussion-link-handler.ts b/src/addon/messages/providers/discussion-link-handler.ts new file mode 100644 index 000000000..d52dde403 --- /dev/null +++ b/src/addon/messages/providers/discussion-link-handler.ts @@ -0,0 +1,89 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// 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 { CoreContentLinksHandlerBase } from '../../../core/contentlinks/classes/base-handler'; +import { CoreContentLinksAction } from '../../../core/contentlinks/providers/delegate'; +import { CoreContentLinksHelperProvider } from '../../../core/contentlinks/providers/helper'; +import { AddonMessagesProvider } from './messages'; +import { CoreSitesProvider } from '../../../providers/sites'; + +/** + * Content links handler for a discussion. + * Match message index URL with params id, user1 or user2. + */ +@Injectable() +export class AddonMessagesDiscussionLinkHandler extends CoreContentLinksHandlerBase { + name = 'AddonMessagesDiscussionLinkHandler'; + pattern = /\/message\/index\.php.*([\?\&](id|user1|user2)=\d+)/; + + constructor(private linkHelper: CoreContentLinksHelperProvider, private messagesProvider: AddonMessagesProvider, + private sitesProvider: CoreSitesProvider) { + super(); + } + + /** + * Get the list of actions for a link (url). + * + * @param {string[]} siteIds List of sites the URL belongs to. + * @param {string} url The URL to treat. + * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} + * @param {number} [courseId] Course ID related to the URL. Optional but recommended. + * @return {CoreContentLinksAction[]|Promise} List of (or promise resolved with list of) actions. + */ + getActions(siteIds: string[], url: string, params: any, courseId?: number): + CoreContentLinksAction[] | Promise { + return [{ + action: (siteId, navCtrl?): void => { + const stateParams = { + userId: parseInt(params.id || params.user2, 10) + }; + // Always use redirect to make it the new history root (to avoid "loops" in history). + this.linkHelper.goInSite(navCtrl, 'AddonMessagesDiscussionPage', stateParams, siteId); + } + }]; + } + + /** + * Check if the handler is enabled for a certain site (site + user) and a URL. + * If not defined, defaults to true. + * + * @param {string} siteId The site ID. + * @param {string} url The URL to treat. + * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} + * @param {number} [courseId] Course ID related to the URL. Optional but recommended. + * @return {boolean|Promise} Whether the handler is enabled for the URL and site. + */ + isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise { + return this.messagesProvider.isPluginEnabled(siteId).then((enabled) => { + if (!enabled) { + return false; + } + + if (typeof params.id == 'undefined' && typeof params.user2 == 'undefined') { + // Other user not defined, cannot treat the URL. + return false; + } + + if (typeof params.user1 != 'undefined') { + // Check if user1 is the current user, since the app only supports current user. + return this.sitesProvider.getSite(siteId).then((site) => { + return parseInt(params.user1, 10) == site.getUserId(); + }); + } + + return true; + }); + } +} diff --git a/src/addon/messages/providers/index-link-handler.ts b/src/addon/messages/providers/index-link-handler.ts new file mode 100644 index 000000000..a4ebfcbd1 --- /dev/null +++ b/src/addon/messages/providers/index-link-handler.ts @@ -0,0 +1,66 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// 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 { CoreContentLinksHandlerBase } from '../../../core/contentlinks/classes/base-handler'; +import { CoreContentLinksAction } from '../../../core/contentlinks/providers/delegate'; +import { CoreContentLinksHelperProvider } from '../../../core/contentlinks/providers/helper'; +import { AddonMessagesProvider } from './messages'; + +/** + * Content links handler for messaging index. + * Match message index URL without params id, user1 or user2. + */ +@Injectable() +export class AddonMessagesIndexLinkHandler extends CoreContentLinksHandlerBase { + name = 'AddonMessagesIndexLinkHandler'; + pattern = /\/message\/index\.php((?![\?\&](id|user1|user2)=\d+).)*$/; + + constructor(private linkHelper: CoreContentLinksHelperProvider, private messagesProvider: AddonMessagesProvider) { + super(); + } + + /** + * Get the list of actions for a link (url). + * + * @param {string[]} siteIds List of sites the URL belongs to. + * @param {string} url The URL to treat. + * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} + * @param {number} [courseId] Course ID related to the URL. Optional but recommended. + * @return {CoreContentLinksAction[]|Promise} List of (or promise resolved with list of) actions. + */ + getActions(siteIds: string[], url: string, params: any, courseId?: number): + CoreContentLinksAction[] | Promise { + return [{ + action: (siteId, navCtrl?): void => { + // Always use redirect to make it the new history root (to avoid "loops" in history). + this.linkHelper.goInSite(navCtrl, 'AddonMessagesIndexPage', undefined, siteId); + } + }]; + } + + /** + * Check if the handler is enabled for a certain site (site + user) and a URL. + * If not defined, defaults to true. + * + * @param {string} siteId The site ID. + * @param {string} url The URL to treat. + * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} + * @param {number} [courseId] Course ID related to the URL. Optional but recommended. + * @return {boolean|Promise} Whether the handler is enabled for the URL and site. + */ + isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise { + return this.messagesProvider.isPluginEnabled(siteId); + } +} diff --git a/src/addon/messages/providers/sync-cron-handler.ts b/src/addon/messages/providers/sync-cron-handler.ts new file mode 100644 index 000000000..4e4226953 --- /dev/null +++ b/src/addon/messages/providers/sync-cron-handler.ts @@ -0,0 +1,48 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// 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 { CoreCronHandler } from '../../../providers/cron'; +import { CoreSitesProvider } from '../../../providers/sites'; +import { AddonMessagesSyncProvider } from './sync'; + +/** + * Synchronization cron handler. + */ +@Injectable() +export class AddonMessagesSyncCronHandler implements CoreCronHandler { + name = 'AddonMessagesSyncCronHandler'; + + constructor(private sitesProvider: CoreSitesProvider, private messagesSync: AddonMessagesSyncProvider) {} + + /** + * Execute the process. + * Receives the ID of the site affected, undefined for all sites. + * + * @param {string} [siteId] ID of the site affected, undefined for all sites. + * @return {Promise} Promise resolved when done, rejected if failure. + */ + execute(siteId?: string): Promise { + return this.messagesSync.syncAllDiscussions(siteId); + } + + /** + * Get the time between consecutive executions. + * + * @return {number} Time between consecutive executions (in ms). + */ + getInterval(): number { + return 300000; // 5 minutes. + } +} diff --git a/src/addon/messages/providers/sync.ts b/src/addon/messages/providers/sync.ts index 90be45371..66adb839f 100644 --- a/src/addon/messages/providers/sync.ts +++ b/src/addon/messages/providers/sync.ts @@ -59,9 +59,11 @@ export class AddonMessagesSyncProvider extends CoreSyncBaseProvider { * @param {Promise} Promise resolved if sync is successful, rejected if sync fails. */ protected syncAllDiscussionsFunc(onlyDeviceOffline: boolean = false, siteId?: string): Promise { - const fn = onlyDeviceOffline ? this.messagesOffline.getAllDeviceOfflineMessages : this.messagesOffline.getAllMessages; + const promise = onlyDeviceOffline ? + this.messagesOffline.getAllDeviceOfflineMessages(siteId) : + this.messagesOffline.getAllMessages(siteId); - return fn(siteId).then((messages) => { + return promise.then((messages) => { const userIds = [], promises = []; diff --git a/src/addon/messages/providers/user-send-message-handler.ts b/src/addon/messages/providers/user-send-message-handler.ts new file mode 100644 index 000000000..aae083c26 --- /dev/null +++ b/src/addon/messages/providers/user-send-message-handler.ts @@ -0,0 +1,77 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// 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 { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '../../../core/user/providers/user-delegate'; +import { CoreSitesProvider } from '../../../providers/sites'; +import { CoreContentLinksHelperProvider } from '../../../core/contentlinks/providers/helper'; +import { AddonMessagesProvider } from './messages'; + +/** + * Profile send message handler. + */ +@Injectable() +export class AddonMessagesSendMessageUserHandler implements CoreUserProfileHandler { + name = 'mmaMessages:sendMessage'; + priority = 1000; + type = CoreUserDelegate.TYPE_COMMUNICATION; + + constructor(private linkHelper: CoreContentLinksHelperProvider, protected sitesProvider: CoreSitesProvider, + private messagesProvider: AddonMessagesProvider) { } + + /** + * Check if handler is enabled. + * + * @return {Promise} Promise resolved with true if enabled, rejected or resolved with false otherwise. + */ + isEnabled(): Promise { + return this.messagesProvider.isPluginEnabled(); + } + + /** + * Check if handler is enabled for this user in this context. + * + * @param {any} user User to check. + * @param {number} courseId Course ID. + * @param {any} [navOptions] Course navigation options for current user. See $mmCourses#getUserNavigationOptions. + * @param {any} [admOptions] Course admin options for current user. See $mmCourses#getUserAdministrationOptions. + * @return {boolean|Promise} Promise resolved with true if enabled, resolved with false otherwise. + */ + isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean | Promise { + return user.id != this.sitesProvider.getCurrentSiteUserId(); + } + + /** + * Returns the data needed to render the handler. + * + * @return {CoreUserProfileHandlerData} Data needed to render the handler. + */ + getDisplayData(user: any, courseId: number): CoreUserProfileHandlerData { + return { + icon: 'send', + title: 'addon.messages.message', + class: 'addon-messages-send-message-handler', + action: (event, navCtrl, user, courseId): void => { + event.preventDefault(); + event.stopPropagation(); + const pageParams = { + showKeyboard: true, + userId: user.id + }; + // Always use redirect to make it the new history root (to avoid "loops" in history). + this.linkHelper.goInSite(navCtrl, 'AddonMessagesDiscussionPage', pageParams); + } + }; + } +} diff --git a/src/classes/base-sync.ts b/src/classes/base-sync.ts index df4a0f0c2..deeb06243 100644 --- a/src/classes/base-sync.ts +++ b/src/classes/base-sync.ts @@ -216,7 +216,7 @@ export class CoreSyncBaseProvider { return Promise.reject(null); } - if (this[syncFunction]) { + if (!this[syncFunction]) { this.logger.debug(`Cannot sync '${syncFunctionLog}' function '${syncFunction}' does not exist.`); return Promise.reject(null); @@ -238,9 +238,7 @@ export class CoreSyncBaseProvider { siteIds.forEach((siteId) => { params['siteId'] = siteId; // Execute function for every site selected. - if (this[syncFunction]) { - sitePromises.push(this[syncFunction].apply(this, params)); - } + sitePromises.push(this[syncFunction].apply(this, params)); }); return Promise.all(sitePromises); diff --git a/src/providers/config.ts b/src/providers/config.ts index 1898d189d..d062a8d22 100644 --- a/src/providers/config.ts +++ b/src/providers/config.ts @@ -67,9 +67,9 @@ export class CoreConfigProvider { }).catch((error) => { if (typeof defaultValue != 'undefined') { return defaultValue; - } else { - return Promise.reject(error); } + + return Promise.reject(error); }); } diff --git a/src/providers/cron.ts b/src/providers/cron.ts index a33af21b2..c3bdc18fb 100644 --- a/src/providers/cron.ts +++ b/src/providers/cron.ts @@ -72,13 +72,13 @@ export interface CoreCronHandler { * Whether the handler is running. Used internally by the provider, there's no need to set it. * @type {boolean} */ - running: boolean; + running?: boolean; /** * Timeout ID for the handler scheduling. Used internally by the provider, there's no need to set it. * @type {number} */ - timeout: number; + timeout?: number; } /* @@ -387,18 +387,18 @@ export class CoreCronDelegate { return; } if (typeof this.handlers[handler.name] != 'undefined') { - this.logger.debug(`The cron handler '${name}' is already registered.`); + this.logger.debug(`The cron handler '${handler.name}' is already registered.`); return; } - this.logger.debug.debug(`Register handler '${name}' in cron.`); + this.logger.debug(`Register handler '${handler.name}' in cron.`); handler.running = false; this.handlers[handler.name] = handler; // Start the handler. - this.startHandler(name); + this.startHandler(handler.name); } /**