MOBILE-3661 grades: Migrate grades handlers

main
Noel De Martin 2021-01-27 11:31:17 +01:00
parent cd6e93b9d1
commit 41f308e62e
8 changed files with 396 additions and 5 deletions

View File

@ -58,7 +58,7 @@ export class CoreLinkDirective implements OnInit {
// @todo: Handle split view?
this.element.addEventListener('click', (event) => {
this.element.addEventListener('click', async (event) => {
if (event.defaultPrevented) {
return; // Link already treated, stop.
}
@ -77,7 +77,8 @@ export class CoreLinkDirective implements OnInit {
if (CoreUtils.instance.isTrueOrOne(this.capture)) {
href = CoreTextUtils.instance.decodeURI(href);
const treated = CoreContentLinksHelper.instance.handleLink(href, undefined, true, true);
const treated = await CoreContentLinksHelper.instance.handleLink(href, undefined, true, true);
if (!treated) {
this.navigate(href, openIn);
}

View File

@ -58,6 +58,7 @@ export class CoreContentLinksHandlerBase implements CoreContentLinksHandler {
* @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.
* @param data Extra data to handle the URL.
* @return List of (or promise resolved with list of) actions.
*/
getActions(
@ -69,6 +70,8 @@ export class CoreContentLinksHandlerBase implements CoreContentLinksHandler {
params: Params,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
courseId?: number,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
data?: unknown,
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
return [];
}

View File

@ -48,7 +48,7 @@ export interface CoreCourseOptionsHandler extends CoreDelegateHandler {
* @return True or promise resolved with true if enabled.
*/
isEnabledForCourse(courseId: number,
accessData: any, // @todo: define type.
accessData: CoreCourseAccessData,
navOptions?: CoreCourseUserAdminOrNavOptionIndexed,
admOptions?: CoreCourseUserAdminOrNavOptionIndexed,
): boolean | Promise<boolean>;
@ -672,3 +672,6 @@ export class CoreCourseOptionsDelegateService extends CoreDelegate<CoreCourseOpt
}
export class CoreCourseOptionsDelegate extends makeSingleton(CoreCourseOptionsDelegateService) {}
// @todo define
export type CoreCourseAccessData = any;

View File

@ -14,9 +14,17 @@
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { Routes } from '@angular/router';
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate';
import { CoreMainMenuRoutingModule } from '@features/mainmenu/mainmenu-routing.module';
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
import { CoreMainMenuDelegate } from '@features/mainmenu/services/mainmenu-delegate';
import { CoreUserDelegate } from '@features/user/services/user-delegate';
import { CoreGradesCourseOptionHandler } from './services/handlers/course-option';
import CoreGradesMainMenuHandler, { CoreGradesMainMenuHandlerService } from './services/handlers/mainmenu';
import { CoreGradesOverviewLinkHandler } from './services/handlers/overview-link';
import { CoreGradesUserHandler } from './services/handlers/user';
import { CoreGradesUserLinkHandler } from './services/handlers/user-link';
const routes: Routes = [
{
@ -26,8 +34,10 @@ const routes: Routes = [
];
@NgModule({
imports: [CoreMainMenuRoutingModule.forChild({ children: routes })],
exports: [CoreMainMenuRoutingModule],
imports: [
CoreMainMenuTabRoutingModule.forChild(routes),
CoreMainMenuRoutingModule.forChild({ children: routes }),
],
providers: [
{
provide: APP_INITIALIZER,
@ -35,6 +45,10 @@ const routes: Routes = [
deps: [],
useValue: () => {
CoreMainMenuDelegate.instance.registerHandler(CoreGradesMainMenuHandler.instance);
CoreUserDelegate.instance.registerHandler(CoreGradesUserHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreGradesUserLinkHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreGradesOverviewLinkHandler.instance);
CoreCourseOptionsDelegate.instance.registerHandler(CoreGradesCourseOptionHandler.instance);
},
},
],

View File

@ -0,0 +1,113 @@
// (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 { CoreCourseProvider } from '@features/course/services/course';
import {
CoreCourseAccessData,
CoreCourseOptionsHandler,
CoreCourseOptionsHandlerData,
} from '@features/course/services/course-options-delegate';
import { CoreCourses, CoreCourseUserAdminOrNavOptionIndexed } from '@features/courses/services/courses';
import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '@features/courses/services/courses-helper';
import { makeSingleton } from '@singletons';
import { CoreGrades } from '../grades';
/**
* Course nav handler.
*/
@Injectable({ providedIn: 'root' })
export class CoreGradesCourseOptionHandlerService implements CoreCourseOptionsHandler {
name = 'CoreGrades';
priority = 400;
/**
* Should invalidate the data to determine if the handler is enabled for a certain course.
*
* @param courseId The course ID.
* @param navOptions Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
* @return Promise resolved when done.
*/
invalidateEnabledForCourse(courseId: number, navOptions?: CoreCourseUserAdminOrNavOptionIndexed): Promise<void> {
if (navOptions && typeof navOptions.grades != 'undefined') {
// No need to invalidate anything.
return Promise.resolve();
}
return CoreCourses.instance.invalidateUserCourses();
}
/**
* Check if the handler is enabled on a site level.
*
* @return Whether or not the handler is enabled on a site level.
*/
isEnabled(): Promise<boolean> {
return Promise.resolve(true);
}
/**
* Whether or not the handler is enabled for a certain course.
*
* @param courseId The course ID.
* @param accessData Access type and data. Default, guest, ...
* @param navOptions Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
* @return True or promise resolved with true if enabled.
*/
isEnabledForCourse(
courseId: number,
accessData: CoreCourseAccessData,
navOptions?: CoreCourseUserAdminOrNavOptionIndexed,
): boolean | Promise<boolean> {
if (accessData && accessData.type == CoreCourseProvider.ACCESS_GUEST) {
return false; // Not enabled for guests.
}
if (navOptions && typeof navOptions.grades != 'undefined') {
return navOptions.grades;
}
return CoreGrades.instance.isPluginEnabledForCourse(courseId);
}
/**
* Returns the data needed to render the handler.
*
* @return Data or promise resolved with the data.
*/
getDisplayData(): CoreCourseOptionsHandlerData | Promise<CoreCourseOptionsHandlerData> {
throw new Error('CoreGradesCourseOptionHandler.getDisplayData is not implemented');
// @todo
// return {
// title: 'core.grades.grades',
// class: 'core-grades-course-handler',
// component: CoreGradesCourseComponent,
// };
}
/**
* Called when a course is downloaded. It should prefetch all the data to be able to see the addon in offline.
*
* @param course The course.
* @return Promise resolved when done.
*/
async prefetch(course: CoreEnrolledCourseDataWithExtraInfoAndOptions): Promise<void> {
await CoreGrades.instance.getCourseGradesTable(course.id, undefined, undefined, true);
}
}
export class CoreGradesCourseOptionHandler extends makeSingleton(CoreGradesCourseOptionHandlerService) {}

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 { CoreGrades } from '../grades';
/**
* Handler to treat links to overview courses grades.
*/
@Injectable({ providedIn: 'root' })
export class CoreGradesOverviewLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreGradesOverviewLinkHandler';
pattern = /\/grade\/report\/overview\/index.php/;
/**
* 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 => {
CoreNavigator.instance.navigateToSitePath('/grades', { 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.
* @return Whether the handler is enabled for the URL and site.
*/
isEnabled(siteId: string): boolean | Promise<boolean> {
return CoreGrades.instance.isCourseGradesEnabled(siteId);
}
}
export class CoreGradesOverviewLinkHandler extends makeSingleton(CoreGradesOverviewLinkHandlerService) {}

View File

@ -0,0 +1,82 @@
// (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 { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreGrades } from '@features/grades/services/grades';
import { CoreGradesHelper } from '@features/grades/services/grades-helper';
import { makeSingleton } from '@singletons';
/**
* Handler to treat links to user grades.
*/
@Injectable({ providedIn: 'root' })
export class CoreGradesUserLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreGradesUserLinkHandler';
pattern = /\/grade\/report(\/user)?\/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}
* @param courseId Course ID related to the URL. Optional but recommended.
* @param data Extra data to handle the URL.
* @return List of (or promise resolved with list of) actions.
*/
getActions(
siteIds: string[],
url: string,
params: Params,
courseId?: number,
data?: { cmid?: string },
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
courseId = courseId || params.id;
data = data || {};
return [{
action: (siteId, navCtrl?): void => {
const userId = params.userid && parseInt(params.userid, 10);
const moduleId = data?.cmid && parseInt(data.cmid, 10) || undefined;
CoreGradesHelper.instance.goToGrades(courseId!, userId, moduleId, navCtrl, 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.
*/
isEnabled(siteId: string, url: string, params: Params, courseId?: number): boolean | Promise<boolean> {
if (!courseId && !params.id) {
return false;
}
return CoreGrades.instance.isPluginEnabledForCourse(courseId || params.id, siteId);
}
}
export class CoreGradesUserLinkHandler extends makeSingleton(CoreGradesUserLinkHandlerService) {}

View File

@ -0,0 +1,118 @@
// (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 { CoreGrades } from '@features/grades/services/grades';
import { CoreUserProfile } from '@features/user/services/user';
import {
CoreUserDelegateService ,
CoreUserProfileHandler,
CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate';
import { CoreNavigator } from '@services/navigator';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
/**
* Profile grades handler.
*/
@Injectable({ providedIn: 'root' })
export class CoreGradesUserHandlerService implements CoreUserProfileHandler {
name = 'CoreGrades:viewGrades';
priority = 400;
type = CoreUserDelegateService.TYPE_NEW_PAGE;
viewGradesEnabledCache = {};
/**
* Clear view grades cache.
* If a courseId and userId are specified, it will only delete the entry for that user and course.
*
* @param courseId Course ID.
* @param userId User ID.
*/
clearViewGradesCache(courseId?: number, userId?: number): void {
if (courseId && userId) {
delete this.viewGradesEnabledCache[this.getCacheKey(courseId, userId)];
} else {
this.viewGradesEnabledCache = {};
}
}
/**
* Get a cache key to identify a course and a user.
*
* @param courseId Course ID.
* @param userId User ID.
* @return Cache key.
*/
protected getCacheKey(courseId: number, userId: number): string {
return courseId + '#' + userId;
}
/**
* Check if handler is enabled.
*
* @return Always enabled.
*/
isEnabled(): Promise<boolean> {
return Promise.resolve(true);
}
/**
* Check if handler is enabled for this user in this context.
*
* @param user User to check.
* @param courseId Course ID.
* @return Promise resolved with true if enabled, resolved with false otherwise.
*/
async isEnabledForUser(user: CoreUserProfile, courseId: number): Promise<boolean> {
const cacheKey = this.getCacheKey(courseId, user.id);
const cache = this.viewGradesEnabledCache[cacheKey];
if (typeof cache != 'undefined') {
return cache;
}
const enabled = await CoreUtils.instance.ignoreErrors(CoreGrades.instance.isPluginEnabledForCourse(courseId), false);
this.viewGradesEnabledCache[cacheKey] = enabled;
return enabled;
}
/**
* Returns the data needed to render the handler.
*
* @return Data needed to render the handler.
*/
getDisplayData(): CoreUserProfileHandlerData {
return {
icon: 'stats-chart',
title: 'core.grades.grades',
class: 'core-grades-user-handler',
action: (event, user, courseId): void => {
event.preventDefault();
event.stopPropagation();
CoreNavigator.instance.navigateToSitePath(`/grades/${courseId}`, {
params: { userId: user.id },
});
},
};
}
}
export class CoreGradesUserHandler extends makeSingleton(CoreGradesUserHandlerService) {}