diff --git a/src/core/course/pages/section/section.ts b/src/core/course/pages/section/section.ts index 7246d3fd9..032a98e49 100644 --- a/src/core/course/pages/section/section.ts +++ b/src/core/course/pages/section/section.ts @@ -303,10 +303,10 @@ export class CoreCourseSectionPage implements OnDestroy { // Load the course format options when course completion is enabled to show completion progress on sections. if (this.course.enablecompletion && this.coursesProvider.isGetCoursesByFieldAvailable()) { - promises.push(this.coursesProvider.getCoursesByField('id', this.course.id).catch(() => { + promises.push(this.coursesProvider.getCourseByField('id', this.course.id).catch(() => { // Ignore errors. - }).then((courses) => { - courses && courses[0] && Object.assign(this.course, courses[0]); + }).then((course) => { + course && Object.assign(this.course, course); if (this.course.courseformatoptions) { this.course.courseformatoptions = this.utils.objectToKeyValueMap(this.course.courseformatoptions, diff --git a/src/core/course/providers/default-format.ts b/src/core/course/providers/default-format.ts index 5fe027ce5..6cc8e1562 100644 --- a/src/core/course/providers/default-format.ts +++ b/src/core/course/providers/default-format.ts @@ -113,10 +113,10 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler { return sections[0]; } else { // Try to retrieve the marker. - promise = this.coursesProvider.getCoursesByField('id', course.id).catch(() => { + promise = this.coursesProvider.getCourseByField('id', course.id).catch(() => { // Ignore errors. - }).then((courses) => { - return courses && courses[0] && courses[0].marker; + }).then((course) => { + return course && course.marker; }); } @@ -156,10 +156,14 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler { * * @param {NavController} navCtrl The NavController instance to use. * @param {any} course The course to open. It should contain a "format" attribute. + * @param {any} [params] Params to pass to the course page. * @return {Promise} Promise resolved when done. */ - openCourse(navCtrl: NavController, course: any): Promise { - return navCtrl.push('CoreCourseSectionPage', { course: course }); + openCourse(navCtrl: NavController, course: any, params?: any): Promise { + params = params || {}; + Object.assign(params, { course: course }); + + return navCtrl.push('CoreCourseSectionPage', params); } /** diff --git a/src/core/course/providers/format-delegate.ts b/src/core/course/providers/format-delegate.ts index 40a2668d4..b65560ced 100644 --- a/src/core/course/providers/format-delegate.ts +++ b/src/core/course/providers/format-delegate.ts @@ -92,9 +92,10 @@ export interface CoreCourseFormatHandler extends CoreDelegateHandler { * * @param {NavController} navCtrl The NavController instance to use. * @param {any} course The course to open. It should contain a "format" attribute. + * @param {any} [params] Params to pass to the course page. * @return {Promise} Promise resolved when done. */ - openCourse?(navCtrl: NavController, course: any): Promise; + openCourse?(navCtrl: NavController, course: any, params?: any): Promise; /** * Return the Component to use to display the course format instead of using the default one. @@ -337,10 +338,11 @@ export class CoreCourseFormatDelegate extends CoreDelegate { * * @param {NavController} navCtrl The NavController instance to use. * @param {any} course The course to open. It should contain a "format" attribute. + * @param {any} [params] Params to pass to the course page. * @return {Promise} Promise resolved when done. */ - openCourse(navCtrl: NavController, course: any): Promise { - return this.executeFunctionOnEnabled(course.format, 'openCourse', [navCtrl, course]); + openCourse(navCtrl: NavController, course: any, params?: any): Promise { + return this.executeFunctionOnEnabled(course.format, 'openCourse', [navCtrl, course, params]); } /** diff --git a/src/core/course/providers/helper.ts b/src/core/course/providers/helper.ts index a79546849..be5872490 100644 --- a/src/core/course/providers/helper.ts +++ b/src/core/course/providers/helper.ts @@ -1401,22 +1401,35 @@ export class CoreCourseHelperProvider { * * @param {NavController} navCtrl The nav controller to use. * @param {any} course Course to open + * @param {any} [params] Params to pass to the course page. + * @return {Promise} Promise resolved when done. */ - openCourse(navCtrl: NavController, course: any): void { + openCourse(navCtrl: NavController, course: any, params?: any): Promise { if (this.sitePluginsProvider.sitePluginPromiseExists('format_' + course.format)) { // This course uses a custom format plugin, wait for the format plugin to finish loading. const loading = this.domUtils.showModalLoading(); - this.sitePluginsProvider.sitePluginLoaded('format_' + course.format).then(() => { + + return this.sitePluginsProvider.sitePluginLoaded('format_' + course.format).then(() => { // The format loaded successfully, but the handlers wont be registered until all site plugins have loaded. if (this.sitePluginsProvider.sitePluginsFinishedLoading) { loading.dismiss(); - this.courseFormatDelegate.openCourse(navCtrl, course); + + return this.courseFormatDelegate.openCourse(navCtrl, course, params); } else { - const observer = this.eventsProvider.on(CoreEventsProvider.SITE_PLUGINS_LOADED, () => { - loading.dismiss(); - this.courseFormatDelegate.openCourse(navCtrl, course); - observer && observer.off(); - }); + // Wait for plugins to be loaded. + const deferred = this.utils.promiseDefer(), + observer = this.eventsProvider.on(CoreEventsProvider.SITE_PLUGINS_LOADED, () => { + loading.dismiss(); + observer && observer.off(); + + this.courseFormatDelegate.openCourse(navCtrl, course, params).then((response) => { + deferred.resolve(response); + }).catch((error) => { + deferred.reject(error); + }); + }); + + return deferred.promise; } }).catch(() => { // The site plugin failed to load. The user needs to restart the app to try loading it again. @@ -1425,7 +1438,7 @@ export class CoreCourseHelperProvider { }); } else { // No custom format plugin. We don't need to wait for anything. - this.courseFormatDelegate.openCourse(navCtrl, course); + return this.courseFormatDelegate.openCourse(navCtrl, course, params); } } } diff --git a/src/core/courses/courses.module.ts b/src/core/courses/courses.module.ts index 81f632e9f..1a7294425 100644 --- a/src/core/courses/courses.module.ts +++ b/src/core/courses/courses.module.ts @@ -20,8 +20,10 @@ import { CoreCoursesDashboardProvider } from './providers/dashboard'; import { CoreCoursesCourseLinkHandler } from './providers/course-link-handler'; import { CoreCoursesIndexLinkHandler } from './providers/courses-index-link-handler'; import { CoreCoursesDashboardLinkHandler } from './providers/dashboard-link-handler'; +import { CoreCoursesEnrolPushClickHandler } from './providers/enrol-push-click-handler'; import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; +import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers/delegate'; // List of providers (without handlers). export const CORE_COURSES_PROVIDERS: any[] = [ @@ -41,18 +43,21 @@ export const CORE_COURSES_PROVIDERS: any[] = [ CoreDashboardMainMenuHandler, CoreCoursesCourseLinkHandler, CoreCoursesIndexLinkHandler, - CoreCoursesDashboardLinkHandler + CoreCoursesDashboardLinkHandler, + CoreCoursesEnrolPushClickHandler ], exports: [] }) export class CoreCoursesModule { constructor(mainMenuDelegate: CoreMainMenuDelegate, contentLinksDelegate: CoreContentLinksDelegate, mainMenuHandler: CoreDashboardMainMenuHandler, courseLinkHandler: CoreCoursesCourseLinkHandler, - indexLinkHandler: CoreCoursesIndexLinkHandler, dashboardLinkHandler: CoreCoursesDashboardLinkHandler) { + indexLinkHandler: CoreCoursesIndexLinkHandler, dashboardLinkHandler: CoreCoursesDashboardLinkHandler, + pushNotificationsDelegate: CorePushNotificationsDelegate, pushClickHandler: CoreCoursesEnrolPushClickHandler) { mainMenuDelegate.registerHandler(mainMenuHandler); contentLinksDelegate.registerHandler(courseLinkHandler); contentLinksDelegate.registerHandler(indexLinkHandler); contentLinksDelegate.registerHandler(dashboardLinkHandler); + pushNotificationsDelegate.registerClickHandler(pushClickHandler); } } diff --git a/src/core/courses/providers/enrol-push-click-handler.ts b/src/core/courses/providers/enrol-push-click-handler.ts new file mode 100644 index 000000000..795b0c603 --- /dev/null +++ b/src/core/courses/providers/enrol-push-click-handler.ts @@ -0,0 +1,79 @@ +// (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 { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreUtilsProvider } from '@providers/utils/utils'; +import { CorePushNotificationsClickHandler } from '@core/pushnotifications/providers/delegate'; +import { CoreCourseHelperProvider } from '@core/course/providers/helper'; +import { CoreLoginHelperProvider } from '@core/login/providers/helper'; + +/** + * Handler for enrol push notifications clicks. + */ +@Injectable() +export class CoreCoursesEnrolPushClickHandler implements CorePushNotificationsClickHandler { + name = 'CoreCoursesEnrolPushClickHandler'; + priority = 200; + + constructor(private utils: CoreUtilsProvider, private domUtils: CoreDomUtilsProvider, + private courseHelper: CoreCourseHelperProvider, private loginHelper: CoreLoginHelperProvider) {} + + /** + * Check if a notification click is handled by this handler. + * + * @param {any} notification The notification to check. + * @return {boolean} Whether the notification click is handled by this handler + */ + handles(notification: any): boolean | Promise { + return this.utils.isTrueOrOne(notification.notif) && notification.moodlecomponent.indexOf('enrol_') === 0 && + notification.name == 'expiry_notification'; + } + + /** + * Handle the notification click. + * + * @param {any} notification The notification to check. + * @return {Promise} Promise resolved when done. + */ + handleClick(notification: any): Promise { + const courseId = Number(notification.courseid), + modal = this.domUtils.showModalLoading(); + + return this.courseHelper.getCourse(courseId, notification.site).then((result) => { + const params: any = { + course: result.course + }; + let page; + + if (notification.contexturl && notification.contexturl.indexOf('user/index.php') != -1) { + // Open the participants tab. + page = 'CoreCourseSectionPage'; + params.selectedTab = 'CoreUserParticipants'; + } else if (result.enrolled) { + // User is still enrolled, open the course. + page = 'CoreCourseSectionPage'; + } else { + // User not enrolled anymore, open the preview page. + page = 'CoreCoursesCoursePreviewPage'; + } + + return this.loginHelper.redirect(page, params, notification.site); + }).catch((error) => { + this.domUtils.showErrorModalDefault(error, 'Error getting course.'); + }).finally(() => { + modal.dismiss(); + }); + } +} diff --git a/src/core/user/providers/participants-link-handler.ts b/src/core/user/providers/participants-link-handler.ts index 910b57eb6..1a219a754 100644 --- a/src/core/user/providers/participants-link-handler.ts +++ b/src/core/user/providers/participants-link-handler.ts @@ -13,9 +13,11 @@ // limitations under the License. import { Injectable } from '@angular/core'; +import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler'; import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate'; import { CoreLoginHelperProvider } from '@core/login/providers/helper'; +import { CoreCourseHelperProvider } from '@core/course/providers/helper'; import { CoreUserProvider } from './user'; /** @@ -27,7 +29,8 @@ export class CoreUserParticipantsLinkHandler extends CoreContentLinksHandlerBase featureName = 'CoreCourseOptionsDelegate_CoreUserParticipants'; pattern = /\/user\/index\.php/; - constructor(private userProvider: CoreUserProvider, private loginHelper: CoreLoginHelperProvider) { + constructor(private userProvider: CoreUserProvider, private loginHelper: CoreLoginHelperProvider, + private courseHelper: CoreCourseHelperProvider, private domUtils: CoreDomUtilsProvider) { super(); } @@ -46,8 +49,22 @@ export class CoreUserParticipantsLinkHandler extends CoreContentLinksHandlerBase return [{ action: (siteId, navCtrl?): void => { - // Always use redirect to make it the new history root (to avoid "loops" in history). - this.loginHelper.redirect('CoreUserParticipantsPage', {courseId: courseId}, siteId); + const modal = this.domUtils.showModalLoading(); + + this.courseHelper.getCourse(courseId, siteId).then((result) => { + const params: any = { + course: result.course, + selectedTab: 'CoreUserParticipants' + }; + + // Always use redirect to make it the new history root (to avoid "loops" in history). + return this.loginHelper.redirect('CoreCourseSectionPage', params, siteId); + }).catch(() => { + // Cannot get course for some reason, just open the participants page. + this.loginHelper.redirect('CoreUserParticipantsPage', {courseId: courseId}, siteId); + }).finally(() => { + modal.dismiss(); + }); } }]; }