MOBILE-3660 courses: Implement missing handlers

main
Pau Ferrer Ocaña 2021-02-03 14:47:02 +01:00
parent bcca120bea
commit 1d39a3ed28
13 changed files with 717 additions and 16 deletions

View File

@ -41,7 +41,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
* @param notification The notification to check.
* @return Whether the notification click is handled by this handler
*/
async handles(notification: NotificationData): Promise<boolean> {
async handles(notification: AddonNotificationsNotificationData): Promise<boolean> {
if (!notification.moodlecomponent) {
// The notification doesn't come from Moodle. Handle it.
return true;
@ -63,7 +63,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
* @param notification Notification to mark.
* @return Promise resolved when done.
*/
protected async markAsRead(notification: NotificationData): Promise<void> {
protected async markAsRead(notification: AddonNotificationsNotificationData): Promise<void> {
const notifId = notification.savedmessageid || notification.id;
if (!notifId) {
@ -81,7 +81,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
* @param notification The notification to check.
* @return Promise resolved when done.
*/
async handleClick(notification: NotificationData): Promise<void> {
async handleClick(notification: AddonNotificationsNotificationData): Promise<void> {
if (notification.customdata?.extendedtext) {
// Display the text in a modal.
@ -133,7 +133,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
export class AddonNotificationsPushClickHandler extends makeSingleton(AddonNotificationsPushClickHandlerService) {}
type NotificationData = CorePushNotificationsNotificationBasicData & {
type AddonNotificationsNotificationData = CorePushNotificationsNotificationBasicData & {
contexturl?: string; // URL related to the notification.
savedmessageid?: number; // Notification ID (optional).
id?: number; // Notification ID (optional).

View File

@ -162,7 +162,7 @@ export class CoreCourseProvider {
* @return Whether the current view is a certain course.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
currentViewIsCourse(navCtrl: any, courseId: number): boolean {
currentViewIsCourse(courseId: number): boolean {
// @todo implement
return false;
}

View File

@ -14,12 +14,19 @@
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { Routes } from '@angular/router';
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreMainMenuHomeRoutingModule } from '@features/mainmenu/pages/home/home-routing.module';
import { CoreMainMenuHomeDelegate } from '@features/mainmenu/services/home-delegate';
import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate';
import { CoreCoursesCourseLinkHandler } from './services/handlers/course-link';
import { CoreCoursesIndexLinkHandler } from './services/handlers/courses-index-link';
import { CoreDashboardHomeHandler, CoreDashboardHomeHandlerService } from './services/handlers/dashboard-home';
import { CoreCoursesDashboardLinkHandler } from './services/handlers/dashboard-link';
import { CoreCoursesEnrolPushClickHandler } from './services/handlers/enrol-push-click';
import { CoreCoursesMyCoursesHomeHandler, CoreCoursesMyCoursesHomeHandlerService } from './services/handlers/my-courses-home';
import { CoreCoursesRequestPushClickHandler } from './services/handlers/request-push-click';
const mainMenuHomeChildrenRoutes: Routes = [
{
@ -59,6 +66,11 @@ const mainMenuHomeSiblingRoutes: Routes = [
useFactory: () => () => {
CoreMainMenuHomeDelegate.instance.registerHandler(CoreDashboardHomeHandler.instance);
CoreMainMenuHomeDelegate.instance.registerHandler(CoreCoursesMyCoursesHomeHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreCoursesCourseLinkHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreCoursesIndexLinkHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreCoursesDashboardLinkHandler.instance);
CorePushNotificationsDelegate.instance.registerClickHandler(CoreCoursesEnrolPushClickHandler.instance);
CorePushNotificationsDelegate.instance.registerClickHandler(CoreCoursesRequestPushClickHandler.instance);
},
},
],

View File

@ -161,6 +161,7 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
* Open page to manage courses storage.
*/
manageCoursesStorage(): void {
// AddonStorageManagerCoursesStoragePage
// @todo this.navCtrl.navigateForward(['/main/home/courses/storage']);
}

View File

@ -1168,8 +1168,6 @@ export class CoreCourses extends makeSingleton(CoreCoursesProvider) {}
/**
* Data sent to the EVENT_MY_COURSES_UPDATED.
*
* @todo course type.
*/
export type CoreCoursesMyCoursesUpdatedEventData = {
action: string; // Action performed.

View File

@ -0,0 +1,342 @@
// (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 { CoreDomUtils } from '@services/utils/dom';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreCourse } from '@features/course/services/course';
import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CoreCourseAnyCourseData, CoreCourses, CoreCoursesProvider, CoreEnrolledCourseData } from '../courses';
import { CoreLogger } from '@singletons/logger';
import { makeSingleton, Translate } from '@singletons';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { Params } from '@angular/router';
import { CoreError } from '@classes/errors/error';
import { CoreUtils } from '@services/utils/utils';
import { CoreTextUtils } from '@services/utils/text';
import { CoreIonLoadingElement } from '@classes/ion-loading';
/**
* Handler to treat links to course view or enrol (except site home).
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreCoursesCourseLinkHandler';
pattern = /((\/enrol\/index\.php)|(\/course\/enrol\.php)|(\/course\/view\.php)).*([?&]id=\d+)/;
protected waitStart = 0;
protected logger: CoreLogger;
constructor() {
super();
this.logger = CoreLogger.getInstance('CoreCoursesCourseLinkHandler');
}
/**
* Get the list of actions for a link (url).
*
* @param siteIds List of sites the URL belongs to.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return List of (or promise resolved with list of) actions.
*/
getActions(
siteIds: string[],
url: string,
params: Params,
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
const courseId = parseInt(params.id, 10);
const sectionId = params.sectionid ? parseInt(params.sectionid, 10) : null;
const pageParams: Params = {
sectionId: sectionId || null,
};
let sectionNumber = typeof params.section != 'undefined' ? parseInt(params.section, 10) : NaN;
if (!sectionId && !sectionNumber) {
// Check if the URL has a hash to navigate to the section.
const matches = url.match(/#section-(\d+)/);
if (matches && matches[1]) {
sectionNumber = parseInt(matches[1], 10);
}
}
if (!isNaN(sectionNumber)) {
pageParams.sectionNumber = sectionNumber;
}
return [{
action: (siteId): void => {
siteId = siteId || CoreSites.instance.getCurrentSiteId();
if (siteId == CoreSites.instance.getCurrentSiteId()) {
// Check if we already are in the course index page.
if (CoreCourse.instance.currentViewIsCourse(courseId)) {
// Current view is this course, just select the contents tab.
CoreCourse.instance.selectCourseTab('', pageParams);
return;
} else {
this.actionEnrol(courseId, url, pageParams).catch(() => {
// Ignore errors.
});
}
} else {
// Make the course the new history root (to avoid "loops" in history).
CoreCourseHelper.instance.getAndOpenCourse(courseId, pageParams, siteId);
}
},
}];
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
* If not defined, defaults to true.
*
* @param siteId The site ID.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return Whether the handler is enabled for the URL and site.
*/
async isEnabled(siteId: string, url: string, params: Params, courseId?: number): Promise<boolean> {
courseId = parseInt(params.id, 10);
if (!courseId) {
return false;
}
// Get the course id of Site Home.
return CoreSites.instance.getSiteHomeId(siteId).then((siteHomeId) => courseId != siteHomeId);
}
/**
* Action to perform when an enrol link is clicked.
*
* @param courseId Course ID.
* @param url Treated URL.
* @param pageParams Params to send to the new page.
* @return Promise resolved when done.
*/
protected async actionEnrol(courseId: number, url: string, pageParams: Params): Promise<void> {
const modal = await CoreDomUtils.instance.showModalLoading();
let course: CoreCourseAnyCourseData | { id: number } | undefined;
// Check if user is enrolled in the course.
try {
course = await CoreCourses.instance.getUserCourse(courseId);
} catch {
course = await this.checkSelfUserCanSelfEnrolOrAccess(courseId, url, modal);
}
// Check if we need to retrieve the course.
if (!course) {
try {
const data = await CoreCourseHelper.instance.getCourse(courseId);
course = data.course;
} catch {
// Cannot get course, return a "fake".
course = { id: courseId };
}
}
modal.dismiss();
// Now open the course.
CoreCourseHelper.instance.openCourse(course, pageParams);
}
/**
* Check if the user can self enrol or access the course.
*
* @param courseId Course ID.
* @param url Treated URL.
* @param modal Modal, to dismiss when needed.
* @return The course after self enrolling or undefined if the user has access but is not enrolled.
*/
protected checkSelfUserCanSelfEnrolOrAccess(
courseId: number,
url: string,
modal: CoreIonLoadingElement,
): Promise<CoreEnrolledCourseData | undefined> {
// User is not enrolled in the course. Check if can self enrol.
return this.canSelfEnrol(courseId).then(async () => {
modal.dismiss();
const isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/);
// The user can self enrol. If it's not a enrolment URL we'll ask for confirmation.
if (!isEnrolUrl) {
try {
await CoreDomUtils.instance.showConfirm(Translate.instance.instant('core.courses.confirmselfenrol'));
} catch {
// User cancelled. Check if the user can view the course contents (guest access or similar).
await CoreCourse.instance.getSections(courseId, false, true);
return;
}
}
// Enrol URL or user confirmed.
try {
return this.selfEnrol(courseId);
} catch (error) {
if (error) {
CoreDomUtils.instance.showErrorModal(error);
}
throw error;
}
}, async (error) => {
// Can't self enrol. Check if the user can view the course contents (guest access or similar).
try {
await CoreCourse.instance.getSections(courseId, false, true);
} catch {
// Error. Show error message and allow the user to open the link in browser.
modal.dismiss();
if (error) {
error = CoreTextUtils.instance.getErrorMessageFromError(error) || error;
}
if (!error) {
error = Translate.instance.instant('core.courses.notenroled');
}
const body = CoreTextUtils.instance.buildSeveralParagraphsMessage(
[error, Translate.instance.instant('core.confirmopeninbrowser')],
);
try {
await CoreDomUtils.instance.showConfirm(body);
CoreSites.instance.getCurrentSite()?.openInBrowserWithAutoLogin(url);
} catch {
// User cancelled.
};
throw error;
}
return undefined;
});
}
/**
* Check if a user can be "automatically" self enrolled in a course.
*
* @param courseId Course ID.
* @return Promise resolved if user can be enrolled in a course, rejected otherwise.
*/
protected async canSelfEnrol(courseId: number): Promise<void> {
// Check that the course has self enrolment enabled.
const methods = await CoreCourses.instance.getCourseEnrolmentMethods(courseId);
let isSelfEnrolEnabled = false;
let instances = 0;
methods.forEach((method) => {
if (method.type == 'self' && method.status) {
isSelfEnrolEnabled = true;
instances++;
}
});
if (!isSelfEnrolEnabled || instances != 1) {
// Self enrol not enabled or more than one instance.
throw new CoreError('Self enrol not enabled in course');
}
}
/**
* Try to self enrol a user in a course.
*
* @param courseId Course ID.
* @param password Password.
* @return Promise resolved when the user is enrolled, rejected otherwise.
*/
protected async selfEnrol(courseId: number, password?: string): Promise<CoreEnrolledCourseData | undefined> {
const modal = await CoreDomUtils.instance.showModalLoading();
try {
await CoreCourses.instance.selfEnrol(courseId, password);
// Success self enrolling the user, invalidate the courses list.
await CoreUtils.instance.ignoreErrors(CoreCourses.instance.invalidateUserCourses());
try {
// Sometimes the list of enrolled courses takes a while to be updated. Wait for it.
return this.waitForEnrolled(courseId, true);
} finally {
modal.dismiss();
}
} catch (error) {
modal.dismiss();
if (error && error.code === CoreCoursesProvider.ENROL_INVALID_KEY) {
// Invalid password. Allow the user to input password.
const title = Translate.instance.instant('core.courses.selfenrolment');
const body = ' '; // Empty message.
const placeholder = Translate.instance.instant('core.courses.password');
if (typeof password != 'undefined') {
// The user attempted a password. Show an error message.
CoreDomUtils.instance.showErrorModal(error);
}
password = await CoreDomUtils.instance.showPrompt(body, title, placeholder);
return this.selfEnrol(courseId, password);
} else {
throw error;
}
}
}
/**
* Wait for the user to be enrolled in a course.
*
* @param courseId The course ID.
* @param first If it's the first call (true) or it's a recursive call (false).
* @return Promise resolved when enrolled or timeout.
*/
protected async waitForEnrolled(courseId: number, first?: boolean): Promise<CoreEnrolledCourseData | undefined> {
if (first) {
this.waitStart = Date.now();
}
// Check if user is enrolled in the course.
await CoreUtils.instance.ignoreErrors(CoreCourses.instance.invalidateUserCourses());
try {
return CoreCourses.instance.getUserCourse(courseId);
} catch {
// Not enrolled, wait a bit and try again.
if (Date.now() - this.waitStart > 60000) {
// Max time reached, stop.
return;
}
return new Promise((resolve, reject): void => {
setTimeout(() => {
this.waitForEnrolled(courseId)
.then(resolve).catch(reject);
}, 5000);
});
}
}
}
export class CoreCoursesCourseLinkHandler extends makeSingleton(CoreCoursesCourseLinkHandlerService) {}

View File

@ -0,0 +1,65 @@
// (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 { Params } from '@angular/router';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { CoreCourses } from '../courses';
import { CoreCoursesMyCoursesHomeHandlerService } from './my-courses-home';
/**
* Handler to treat links to course index (list of courses).
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesIndexLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreCoursesIndexLinkHandler';
featureName = 'CoreMainMenuDelegate_CoreCourses';
pattern = /\/course\/?(index\.php.*)?$/;
/**
* Get the list of actions for a link (url).
*
* @param siteIds List of sites the URL belongs to.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @return List of (or promise resolved with list of) actions.
*/
getActions(siteIds: string[], url: string, params: Params): CoreContentLinksAction[] {
return [{
action: (siteId): void => {
let pageName = CoreCoursesMyCoursesHomeHandlerService.PAGE_NAME;
if (CoreCourses.instance.isGetCoursesByFieldAvailable()) {
if (params.categoryid) {
pageName += '/categories/' + params.categoryid;
} else {
pageName += '/all';
}
} else {
// By default, go to My Courses.
pageName += '/my';
}
CoreNavigator.instance.navigateToSitePath(pageName, { siteId });
},
}];
}
}
export class CoreCoursesIndexLinkHandler extends makeSingleton(CoreCoursesIndexLinkHandlerService) {}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { AddonBlockTimeline } from '@addons/block/timeline/services/timeline';
import { Injectable } from '@angular/core';
import { CoreBlockDelegate } from '@features/block/services/block-delegate';
import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate';
@ -45,9 +46,35 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler
* @return Whether or not the handler is enabled on a site level.
*/
async isEnabledForSite(siteId?: string): Promise<boolean> {
const blocks = await CoreCoursesDashboard.instance.getDashboardBlocks(undefined, siteId);
const promises: Promise<void>[] = [];
let blocksEnabled = false;
let dashboardAvailable = false;
return CoreBlockDelegate.instance.hasSupportedBlock(blocks);
// Check if blocks and 3.6 dashboard is enabled.
promises.push(CoreBlockDelegate.instance.areBlocksDisabled(siteId).then((disabled) => {
blocksEnabled = !disabled;
return;
}));
promises.push(CoreCoursesDashboard.instance.isAvailable().then((available) => {
dashboardAvailable = available;
return;
}));
await Promise.all(promises);
if (dashboardAvailable && blocksEnabled) {
const blocks = await CoreCoursesDashboard.instance.getDashboardBlocks(undefined, siteId);
return CoreBlockDelegate.instance.hasSupportedBlock(blocks);
}
// Check if my overview is enabled. If it's enabled we will fake enabled blocks.
const timelineEnabled = await AddonBlockTimeline.instance.isAvailable();
return timelineEnabled && blocksEnabled;
}
/**

View File

@ -0,0 +1,57 @@
// (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 { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { CoreDashboardHomeHandler, CoreDashboardHomeHandlerService } from './dashboard-home';
/**
* Handler to treat links to my overview.
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesDashboardLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreCoursesMyOverviewLinkHandler';
pattern = /\/my\/?$/;
/**
* Get the list of actions for a link (url).
*
* @return List of (or promise resolved with list of) actions.
*/
getActions(): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
return [{
action: (siteId): void => {
// Use redirect to select the tab.
CoreNavigator.instance.navigateToSitePath(CoreDashboardHomeHandlerService.PAGE_NAME, { siteId });
},
}];
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
*
* @param siteId The site ID.
* @return Whether the handler is enabled for the URL and site.
*/
isEnabled(siteId: string): boolean | Promise<boolean> {
return CoreDashboardHomeHandler.instance.isEnabledForSite(siteId);
}
}
export class CoreCoursesDashboardLinkHandler extends makeSingleton(CoreCoursesDashboardLinkHandlerService) {}

View File

@ -0,0 +1,91 @@
// (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 { Params } from '@angular/router';
import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
/**
* Handler for enrol push notifications clicks.
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesEnrolPushClickHandlerService implements CorePushNotificationsClickHandler {
name = 'CoreCoursesEnrolPushClickHandler';
priority = 200;
/**
* Check if a notification click is handled by this handler.
*
* @param notification The notification to check.
* @return Whether the notification click is handled by this handler
*/
async handles(notification: CorePushNotificationsNotificationBasicData): Promise<boolean> {
return CoreUtils.instance.isTrueOrOne(notification.notif) && notification.moodlecomponent?.indexOf('enrol_') === 0 &&
notification.name == 'expiry_notification';
}
/**
* Handle the notification click.
*
* @param notification The notification to check.
* @return Promise resolved when done.
*/
async handleClick(notification: CoreCoursesEnrolNotificationData): Promise<void> {
const courseId = notification.courseid;
const modal = await CoreDomUtils.instance.showModalLoading();
try {
const result = await CoreCourseHelper.instance.getCourse(courseId, notification.site);
const params: Params = {
course: result.course,
};
let page: string;
if (notification.contexturl?.indexOf('user/index.php') != -1) {
// Open the participants tab.
page = 'course';
params.selectedTab = 'user_participants'; // @todo: Set this when participants is done.
} else if (result.enrolled) {
// User is still enrolled, open the course.
page = 'course';
} else {
// User not enrolled anymore, open the preview page.
page = 'courses/preview';;
}
await CoreNavigator.instance.navigateToSitePath(page, { params, siteId: notification.site });
} catch (error) {
CoreDomUtils.instance.showErrorModalDefault(error, 'Error getting course.');
} finally {
modal.dismiss();
}
}
}
export class CoreCoursesEnrolPushClickHandler extends makeSingleton(CoreCoursesEnrolPushClickHandlerService) {}
type CoreCoursesEnrolNotificationData = CorePushNotificationsNotificationBasicData & {
courseid: number; // Course ID related to the notification.
contexturl?: string; // Context URL related to the notification.
};

View File

@ -17,6 +17,7 @@ import { CoreBlockDelegate } from '@features/block/services/block-delegate';
import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate';
import { CoreSiteHome } from '@features/sitehome/services/sitehome';
import { makeSingleton } from '@singletons';
import { CoreCourses } from '../courses';
import { CoreCoursesDashboard } from '../dashboard';
/**
@ -46,6 +47,12 @@ export class CoreCoursesMyCoursesHomeHandlerService implements CoreMainMenuHomeH
* @return Whether or not the handler is enabled on a site level.
*/
async isEnabledForSite(siteId?: string): Promise<boolean> {
const disabled = await CoreCourses.instance.isMyCoursesDisabled(siteId);
if (disabled) {
return false;
}
const blocks = await CoreCoursesDashboard.instance.getDashboardBlocks(undefined, siteId);
return !CoreBlockDelegate.instance.hasSupportedBlock(blocks)&& !CoreSiteHome.instance.isAvailable(siteId);

View File

@ -0,0 +1,103 @@
// (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 { Params } from '@angular/router';
import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
import { CoreCourses } from '../courses';
/**
* Handler for course request push notifications clicks.
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesRequestPushClickHandlerService implements CorePushNotificationsClickHandler {
name = 'CoreCoursesRequestPushClickHandler';
priority = 200;
/**
* Check if a notification click is handled by this handler.
*
* @param notification The notification to check.
* @return Whether the notification click is handled by this handler
*/
async handles(notification: CorePushNotificationsNotificationBasicData): Promise<boolean> {
// Don't support 'courserequestrejected', that way the app will open the notifications page.
return CoreUtils.instance.isTrueOrOne(notification.notif) && notification.moodlecomponent == 'moodle' &&
(notification.name == 'courserequested' || notification.name == 'courserequestapproved');
}
/**
* Handle the notification click.
*
* @param notification The notification to check.
* @return Promise resolved when done.
*/
async handleClick(notification: CoreCoursesRequestNotificationData): Promise<void> {
const courseId = notification.courseid;
if (notification.name == 'courserequested') {
// Feature not supported in the app, open in browser.
const site = await CoreSites.instance.getSite(notification.site);
const url = CoreTextUtils.instance.concatenatePaths(site.getURL(), 'course/pending.php');
await site.openInBrowserWithAutoLogin(url);
return;
}
// Open the course.
const modal = await CoreDomUtils.instance.showModalLoading();
await CoreUtils.instance.ignoreErrors(CoreCourses.instance.invalidateUserCourses(notification.site));
try {
const result = await CoreCourseHelper.instance.getCourse(courseId, notification.site);
const params: Params = {
course: result.course,
};
let page: string;
if (result.enrolled) {
// User is still enrolled, open the course.
page = 'course';
} else {
// User not enrolled (shouldn't happen), open the preview page.
page = 'courses/preview';
}
await CoreNavigator.instance.navigateToSitePath(page, { params, siteId: notification.site });
} catch (error) {
CoreDomUtils.instance.showErrorModalDefault(error, 'Error getting course.');
} finally {
modal.dismiss();
}
}
}
export class CoreCoursesRequestPushClickHandler extends makeSingleton(CoreCoursesRequestPushClickHandlerService) {}
type CoreCoursesRequestNotificationData = CorePushNotificationsNotificationBasicData & {
courseid: number; // Course ID related to the notification.
};

View File

@ -14,6 +14,7 @@
import { Injectable } from '@angular/core';
import { makeSingleton } from '@singletons';
import { CoreMainMenuHomeDelegate } from '../home-delegate';
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../mainmenu-delegate';
/**
@ -24,7 +25,7 @@ export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler {
static readonly PAGE_NAME = 'home';
name = 'CoreMainMenuHome';
name = 'CoreHome';
priority = 1100;
/**
@ -39,13 +40,10 @@ export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler {
/**
* Check if the handler is enabled on a certain site.
*
* @param siteId Site ID. If not defined, current site.
* @return Whether or not the handler is enabled on a site level.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async isEnabledForSite(siteId?: string): Promise<boolean> {
// @todo
return true;
async isEnabledForSite(): Promise<boolean> {
return CoreMainMenuHomeDelegate.instance.getHandlers().length > 0;
}
/**
@ -55,7 +53,7 @@ export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler {
*/
getDisplayData(): CoreMainMenuHandlerData {
return {
icon: 'fa-home',
icon: 'fas-home',
title: 'core.mainmenu.home',
page: CoreMainMenuHomeHandlerService.PAGE_NAME,
// @todo: subPage? The page can change due to core-tabs.