MOBILE-4498 completion: Use adv features to check if completion is on
parent
3cc03713ae
commit
41f005d65a
|
@ -64,6 +64,7 @@ jobs:
|
|||
"@addon_block_timeline"
|
||||
"@addon_calendar"
|
||||
"@addon_competency"
|
||||
"@addon_coursecompletion"
|
||||
"@addon_messages"
|
||||
"@addon_mod_assign"
|
||||
"@addon_mod_bigbluebuttonbn"
|
||||
|
|
|
@ -18,6 +18,7 @@ import { CoreBlockOnlyTitleComponent } from '@features/block/components/only-tit
|
|||
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
|
||||
import { CoreCourseBlock } from '@features/course/services/course';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonCourseCompletion } from '@addons/coursecompletion/services/coursecompletion';
|
||||
|
||||
/**
|
||||
* Block handler.
|
||||
|
@ -31,7 +32,27 @@ export class AddonBlockCompletionStatusHandlerService extends CoreBlockBaseHandl
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getDisplayData(block: CoreCourseBlock, contextLevel: string, instanceId: number): CoreBlockHandlerData {
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonCourseCompletion.isCompletionEnabledInSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async getDisplayData(
|
||||
block: CoreCourseBlock,
|
||||
contextLevel: string,
|
||||
instanceId: number,
|
||||
): Promise<undefined | CoreBlockHandlerData> {
|
||||
if (contextLevel !== 'course') {
|
||||
return;
|
||||
}
|
||||
|
||||
const courseEnabled = await AddonCourseCompletion.isPluginViewEnabledForCourse(instanceId);
|
||||
if (!courseEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
title: 'addon.block_completionstatus.pluginname',
|
||||
class: 'addon-block-completion-status',
|
||||
|
|
|
@ -18,6 +18,7 @@ import { CoreBlockOnlyTitleComponent } from '@features/block/components/only-tit
|
|||
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
|
||||
import { CoreCourseBlock } from '@features/course/services/course';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonCourseCompletion } from '@addons/coursecompletion/services/coursecompletion';
|
||||
|
||||
/**
|
||||
* Block handler.
|
||||
|
@ -31,7 +32,27 @@ export class AddonBlockSelfCompletionHandlerService extends CoreBlockBaseHandler
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getDisplayData(block: CoreCourseBlock, contextLevel: string, instanceId: number): CoreBlockHandlerData {
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonCourseCompletion.isCompletionEnabledInSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async getDisplayData(
|
||||
block: CoreCourseBlock,
|
||||
contextLevel: string,
|
||||
instanceId: number,
|
||||
): Promise<undefined | CoreBlockHandlerData> {
|
||||
if (contextLevel !== 'course') {
|
||||
return;
|
||||
}
|
||||
|
||||
const courseEnabled = await AddonCourseCompletion.isPluginViewEnabledForCourse(instanceId);
|
||||
if (!courseEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
title: 'addon.block_selfcompletion.pluginname',
|
||||
class: 'addon-block-self-completion',
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreCourses } from '@features/courses/services/courses';
|
||||
import { CoreCourseAnyCourseData, CoreCourses } from '@features/courses/services/courses';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
import { CoreStatusWithWarningsWSResponse, CoreWSExternalWarning } from '@services/ws';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
@ -40,6 +40,44 @@ export class AddonCourseCompletionProvider {
|
|||
this.logger = CoreLogger.getInstance('AddonCourseCompletion');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether completion is available in a certain site.
|
||||
*
|
||||
* @param site Site. If not defined, use current site.
|
||||
* @returns True if available.
|
||||
*/
|
||||
isCompletionEnabledInSite(site?: CoreSite): boolean {
|
||||
site = site || CoreSites.getCurrentSite();
|
||||
|
||||
return !!site && site.canUseAdvancedFeature('enablecompletion');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether completion is available in a certain course.
|
||||
*
|
||||
* @param course Course.
|
||||
* @param site Site. If not defined, use current site.
|
||||
* @returns True if available.
|
||||
*/
|
||||
isCompletionEnabledInCourse(course: CoreCourseAnyCourseData, site?: CoreSite): boolean {
|
||||
if (!this.isCompletionEnabledInSite(site)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isCompletionEnabledInCourseObject(course);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether completion is enabled in a certain course object.
|
||||
*
|
||||
* @param course Course object.
|
||||
* @returns True if completion is enabled, false otherwise.
|
||||
*/
|
||||
protected isCompletionEnabledInCourseObject(course: CoreCourseAnyCourseData): boolean {
|
||||
// Undefined means it's not supported, so it's enabled by default.
|
||||
return course.enablecompletion !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the user can mark a course as self completed.
|
||||
* It can if it's configured in the course and it hasn't been completed yet.
|
||||
|
@ -180,7 +218,7 @@ export class AddonCourseCompletionProvider {
|
|||
* @returns True if plugin enabled, false otherwise.
|
||||
*/
|
||||
isPluginViewEnabled(): boolean {
|
||||
return CoreSites.isLoggedIn();
|
||||
return CoreSites.isLoggedIn() && this.isCompletionEnabledInSite();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,26 +228,19 @@ export class AddonCourseCompletionProvider {
|
|||
* @param preferCache True if shouldn't call WS if data is cached, false otherwise.
|
||||
* @returns Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
|
||||
*/
|
||||
async isPluginViewEnabledForCourse(courseId?: number, preferCache: boolean = true): Promise<boolean> {
|
||||
if (!courseId) {
|
||||
async isPluginViewEnabledForCourse(courseId?: number, preferCache = true): Promise<boolean> {
|
||||
if (!courseId || !this.isCompletionEnabledInSite()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const course = await CoreCourses.getUserCourse(courseId, preferCache);
|
||||
|
||||
if (course) {
|
||||
if (course.enablecompletion !== undefined && !course.enablecompletion) {
|
||||
// Completion not enabled for the course.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (course.completionhascriteria !== undefined && !course.completionhascriteria) {
|
||||
// No criteria, cannot view completion.
|
||||
return false;
|
||||
}
|
||||
if (!course) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Check completion is enabled in the course and it has criteria, to view completion.
|
||||
return this.isCompletionEnabledInCourseObject(course) && course.completionhascriteria !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
@addon_coursecompletion @app @javascript
|
||||
Feature: Course completion navigation
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category | enablecompletion | showcompletionconditions |
|
||||
| Course 1 | C1 | 0 | 1 | 1 |
|
||||
| Course 2 | C2 | 0 | | |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| teacher1 | C2 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student1 | C2 | student |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| grade[modgrade_type] | Point |
|
||||
| grade[modgrade_point] | 100 |
|
||||
| gradepass | 70 |
|
||||
| completion | 2 |
|
||||
| completionusegrade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
And the following "activity" exists:
|
||||
| activity | page |
|
||||
| course | C2 |
|
||||
| name | P1 |
|
||||
And I enable "selfcompletion" "block" plugin
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference |
|
||||
| completionstatus | Course | C1 |
|
||||
| selfcompletion | Course | C1 |
|
||||
| activity_modules | Course | C1 |
|
||||
| completionstatus | Course | C2 |
|
||||
| selfcompletion | Course | C2 |
|
||||
| activity_modules | Course | C2 |
|
||||
And the following config values are set as admin:
|
||||
| enablecompletion | 1 |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I click on "Condition: Activity completion" "link"
|
||||
And I set the field "Assignment - Test assignment name" to "1"
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| id_criteria_self | 1 |
|
||||
And I press "Save changes"
|
||||
|
||||
Scenario: Completion is available only when enabled for the course
|
||||
Given I entered the course "Course 1" as "student1" in the app
|
||||
When I press "Open block drawer" in the app
|
||||
Then I should find "Course completion status" in the app
|
||||
And I should find "Self completion" in the app
|
||||
When I press "Close" in the app
|
||||
And I press "Completion" in the app
|
||||
Then I should find "Status" in the app
|
||||
|
||||
Given I entered the course "Course 2" as "student1" in the app
|
||||
When I press "Open block drawer" in the app
|
||||
Then I should not find "Course completion status" in the app
|
||||
And I should not find "Self completion" in the app
|
||||
When I press "Close" in the app
|
||||
Then I should not find "Completion" in the app
|
||||
|
||||
Given the following config values are set as admin:
|
||||
| enablecompletion | 0 |
|
||||
Then I entered the course "Course 1" as "student1" in the app
|
||||
And I pull to refresh in the app
|
||||
When I press "Open block drawer" in the app
|
||||
Then I should not find "Course completion status" in the app
|
||||
And I should not find "Self completion" in the app
|
||||
When I press "Close" in the app
|
||||
Then I should not find "Completion" in the app
|
|
@ -22,6 +22,7 @@ import {
|
|||
import { CoreCourseHelper, CoreCourseModuleData, CoreCourseSection } from '@features/course/services/course-helper';
|
||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { ModalController } from '@singletons';
|
||||
|
@ -61,7 +62,7 @@ export class CoreCourseCourseIndexComponent implements OnInit {
|
|||
return;
|
||||
}
|
||||
|
||||
let completionEnabled = !!this.course.enablecompletion;
|
||||
let completionEnabled = CoreCoursesHelper.isCompletionEnabledInCourse(this.course);
|
||||
if (completionEnabled && 'completionusertracked' in this.course && this.course.completionusertracked !== undefined) {
|
||||
completionEnabled = this.course.completionusertracked;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import {
|
|||
} from '@singletons/events';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreRefreshContext, CORE_REFRESH_CONTEXT } from '@/core/utils/refresh-context';
|
||||
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
|
||||
|
||||
/**
|
||||
* Page that displays the contents of a course.
|
||||
|
@ -221,7 +222,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy, CoreRefreshCon
|
|||
let completionStatus: Record<string, CoreCourseCompletionActivityStatus> = {};
|
||||
|
||||
// Get the completion status.
|
||||
if (this.course.enablecompletion !== false) {
|
||||
if (CoreCoursesHelper.isCompletionEnabledInCourse(this.course)) {
|
||||
const sectionWithModules = sections.find((section) => section.modules.length > 0);
|
||||
|
||||
if (sectionWithModules && sectionWithModules.modules[0].completion !== undefined) {
|
||||
|
@ -265,7 +266,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy, CoreRefreshCon
|
|||
protected async loadCourseFormatOptions(): Promise<void> {
|
||||
|
||||
// Load the course format options when course completion is enabled to show completion progress on sections.
|
||||
if (!this.course.enablecompletion) {
|
||||
if (!CoreCoursesHelper.isCompletionEnabledInCourse(this.course)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
|
||||
import {
|
||||
CoreCourseAnyCourseData,
|
||||
CoreCourseAnyCourseDataWithOptions,
|
||||
CoreCourses,
|
||||
CoreCourseSearchedData,
|
||||
|
@ -31,6 +32,7 @@ import { zipIncludingComplete } from '@/core/utils/rxjs';
|
|||
import { catchError, map } from 'rxjs/operators';
|
||||
import { chainRequests, WSObservable } from '@classes/sites/authenticated-site';
|
||||
import { LazyRoutesModule } from '@/app/app-routing.module';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
|
||||
// Id for a course item representing all courses (for example, for course filters).
|
||||
export const ALL_COURSES_ID = -1;
|
||||
|
@ -363,7 +365,7 @@ export class CoreCoursesHelperProvider {
|
|||
return of(course);
|
||||
}
|
||||
|
||||
if (course.enablecompletion !== undefined && !course.enablecompletion) {
|
||||
if (!this.isCompletionEnabledInCourse(course)) {
|
||||
// Completion is disabled for this course, there is no need to fetch the completion status.
|
||||
return of(course);
|
||||
}
|
||||
|
@ -437,6 +439,18 @@ export class CoreCoursesHelperProvider {
|
|||
return import('../courses-my-lazy.module').then(m => m.CoreCoursesMyLazyModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether completion is available in a certain course.
|
||||
* This is a temporary function to be used until we move AddonCourseCompletion to core folder (MOBILE-4537).
|
||||
*
|
||||
* @param course Course.
|
||||
* @param site Site. If not defined, use current site.
|
||||
* @returns True if available.
|
||||
*/
|
||||
isCompletionEnabledInCourse(course: CoreCourseAnyCourseData, site?: CoreSite): boolean {
|
||||
return AddonCourseCompletion.isCompletionEnabledInCourse(course, site);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const CoreCoursesHelper = makeSingleton(CoreCoursesHelperProvider);
|
||||
|
|
Loading…
Reference in New Issue