From 3cc03713ae7904a8f7749205ef455f9dcdd72225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 28 Feb 2024 15:37:49 +0100 Subject: [PATCH 1/8] MOBILE-4498 tags: Use advanced features to check if tags are enabled --- .github/workflows/acceptance.yml | 1 + .../block/blogtags/services/block-handler.ts | 12 +++++++ .../block/tags/services/block-handler.ts | 8 +++++ src/core/classes/delegate.ts | 17 +++++++++- .../tag/services/handlers/mainmenu.ts | 9 +----- .../tag/services/tag-area-delegate.ts | 8 +++++ src/core/features/tag/services/tag.ts | 3 +- .../tag/tests/behat/navigation.feature | 31 +++++++++++++++++++ 8 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 src/core/features/tag/tests/behat/navigation.feature diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index b0135037c..7c40a9c0c 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -93,6 +93,7 @@ jobs: "@core_search" "@core_settings" "@core_siteplugins" + "@core_tag" "@core_user" "@core_usertour" ) diff --git a/src/addons/block/blogtags/services/block-handler.ts b/src/addons/block/blogtags/services/block-handler.ts index 1ace929ac..66ba21369 100644 --- a/src/addons/block/blogtags/services/block-handler.ts +++ b/src/addons/block/blogtags/services/block-handler.ts @@ -18,6 +18,8 @@ import { CoreBlockHandlerData } from '@features/block/services/block-delegate'; import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler'; import { AddonBlockBlogTagsComponent } from '../components/blogtags/blogtags'; import { makeSingleton } from '@singletons'; +import { CoreTag } from '@features/tag/services/tag'; +import { AddonBlog } from '@addons/blog/services/blog'; /** * Block handler. @@ -28,6 +30,16 @@ export class AddonBlockBlogTagsHandlerService extends CoreBlockBaseHandler { name = 'AddonBlockBlogTags'; blockName = 'blog_tags'; + /** + * @inheritdoc + */ + async isEnabled(): Promise { + const tags = await CoreTag.areTagsAvailable(); + const blogs = await AddonBlog.isPluginEnabled(); + + return blogs && tags; + } + /** * Returns the data needed to render the block. * diff --git a/src/addons/block/tags/services/block-handler.ts b/src/addons/block/tags/services/block-handler.ts index 723e16f43..6abfb7690 100644 --- a/src/addons/block/tags/services/block-handler.ts +++ b/src/addons/block/tags/services/block-handler.ts @@ -18,6 +18,7 @@ import { CoreBlockHandlerData } from '@features/block/services/block-delegate'; import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler'; import { AddonBlockTagsComponent } from '../components/tags/tags'; import { makeSingleton } from '@singletons'; +import { CoreTag } from '@features/tag/services/tag'; /** * Block handler. @@ -28,6 +29,13 @@ export class AddonBlockTagsHandlerService extends CoreBlockBaseHandler { name = 'AddonBlockTags'; blockName = 'tags'; + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return await CoreTag.areTagsAvailable(); + } + /** * Returns the data needed to render the block. * diff --git a/src/core/classes/delegate.ts b/src/core/classes/delegate.ts index 2dd5141c9..ba2b73b0f 100644 --- a/src/core/classes/delegate.ts +++ b/src/core/classes/delegate.ts @@ -111,6 +111,15 @@ export class CoreDelegate { } } + /** + * Check if the delegate is enabled so handlers are not updated if not.. + * + * @returns Whether the delegate is enabled. + */ + async isEnabled(): Promise { + return true; + } + /** * Execute a certain function in a enabled handler. * If the handler isn't found or function isn't defined, call the same function in the default handler. @@ -315,6 +324,12 @@ export class CoreDelegate { * @returns Resolved when done. */ async updateHandlers(): Promise { + const enabled = await this.isEnabled(); + + if (!enabled) { + return; + } + const promises: Promise[] = []; const now = Date.now(); @@ -329,7 +344,7 @@ export class CoreDelegate { try { await Promise.all(promises); - } catch (e) { + } catch { // Never reject } diff --git a/src/core/features/tag/services/handlers/mainmenu.ts b/src/core/features/tag/services/handlers/mainmenu.ts index cd88b5740..72d9e9145 100644 --- a/src/core/features/tag/services/handlers/mainmenu.ts +++ b/src/core/features/tag/services/handlers/mainmenu.ts @@ -15,7 +15,6 @@ import { Injectable } from '@angular/core'; import { CoreTag } from '../tag'; import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@features/mainmenu/services/mainmenu-delegate'; -import { CoreUtils } from '@services/utils/utils'; import { makeSingleton } from '@singletons'; /** @@ -35,13 +34,7 @@ export class CoreTagMainMenuHandlerService implements CoreMainMenuHandler { * @returns Whether or not the handler is enabled on a site level. */ async isEnabled(): Promise { - const available = await CoreTag.areTagsAvailable(); - if (!available) { - return false; - } - - // The only way to check whether tags are enabled on web is to perform a WS call. - return CoreUtils.promiseWorks(CoreTag.getTagCollections()); + return await CoreTag.areTagsAvailable(); } /** diff --git a/src/core/features/tag/services/tag-area-delegate.ts b/src/core/features/tag/services/tag-area-delegate.ts index 5864ea471..64462d5bb 100644 --- a/src/core/features/tag/services/tag-area-delegate.ts +++ b/src/core/features/tag/services/tag-area-delegate.ts @@ -15,6 +15,7 @@ import { Injectable, Type } from '@angular/core'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { makeSingleton } from '@singletons'; +import { CoreTag } from './tag'; /** * Interface that all tag area handlers must implement. @@ -53,6 +54,13 @@ export class CoreTagAreaDelegateService extends CoreDelegate super('CoreTagAreaDelegate', true); } + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return CoreTag.areTagsAvailable(); + } + /** * Returns the display name string for this area. * diff --git a/src/core/features/tag/services/tag.ts b/src/core/features/tag/services/tag.ts index cc5261426..ccbc08d6a 100644 --- a/src/core/features/tag/services/tag.ts +++ b/src/core/features/tag/services/tag.ts @@ -53,7 +53,8 @@ export class CoreTagProvider { areTagsAvailableInSite(site?: CoreSite): boolean { site = site || CoreSites.getCurrentSite(); - return !!site && site.wsAvailable('core_tag_get_tagindex_per_area') && + return !!site && site.canUseAdvancedFeature('usetags') && + site.wsAvailable('core_tag_get_tagindex_per_area') && site.wsAvailable('core_tag_get_tag_cloud') && site.wsAvailable('core_tag_get_tag_collections') && !site.isFeatureDisabled('NoDelegate_CoreTag'); diff --git a/src/core/features/tag/tests/behat/navigation.feature b/src/core/features/tag/tests/behat/navigation.feature new file mode 100644 index 000000000..0740d8be4 --- /dev/null +++ b/src/core/features/tag/tests/behat/navigation.feature @@ -0,0 +1,31 @@ +@core_tag @app @javascript +Feature: Tag navigation + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | interests | + | user1 | User | 1 | user1@example.com | Cat | + | user2 | User | 2 | user1@example.com | Cat, Dog | + | user3 | User | 3 | user1@example.com | Dog | + And the following "courses" exist: + | fullname | shortname | tags | + | Course 1 | c1 | Cat, Dog | + | Course 2 | c2 | Cat | + | Course 3 | c3 | Cat | + | Course 4 | c4 | Cat | + | Course 5 | c5 | Cat | + | Course 6 | c6 | Cat | + | Course 7 | c7 | Cat | + + Scenario: Tag menu item is found in the more menu when completion is enabled + Given I entered the app as "user1" + When I press the more menu button in the app + And I press "Tags" in the app + Then I should find "Cat" in the app + Then I should find "Dog" in the app + + Given the following config values are set as admin: + | usetags | 0 | + And I entered the app as "user1" + When I press the more menu button in the app + Then I should not find "Tags" in the app From 41f005d65aa38e6c8b4831e9e471d38325296303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 28 Feb 2024 16:04:32 +0100 Subject: [PATCH 2/8] MOBILE-4498 completion: Use adv features to check if completion is on --- .github/workflows/acceptance.yml | 1 + .../services/block-handler.ts | 23 +++++- .../selfcompletion/services/block-handler.ts | 23 +++++- .../services/coursecompletion.ts | 61 +++++++++++---- .../tests/behat/navigation.feature | 78 +++++++++++++++++++ .../components/course-index/course-index.ts | 3 +- .../course/pages/contents/contents.ts | 5 +- .../courses/services/courses-helper.ts | 16 +++- 8 files changed, 189 insertions(+), 21 deletions(-) create mode 100644 src/addons/coursecompletion/tests/behat/navigation.feature diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 7c40a9c0c..f63cd5edb 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -64,6 +64,7 @@ jobs: "@addon_block_timeline" "@addon_calendar" "@addon_competency" + "@addon_coursecompletion" "@addon_messages" "@addon_mod_assign" "@addon_mod_bigbluebuttonbn" diff --git a/src/addons/block/completionstatus/services/block-handler.ts b/src/addons/block/completionstatus/services/block-handler.ts index 602be93b2..13cf265c8 100644 --- a/src/addons/block/completionstatus/services/block-handler.ts +++ b/src/addons/block/completionstatus/services/block-handler.ts @@ -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 { + return AddonCourseCompletion.isCompletionEnabledInSite(); + } + + /** + * @inheritdoc + */ + async getDisplayData( + block: CoreCourseBlock, + contextLevel: string, + instanceId: number, + ): Promise { + if (contextLevel !== 'course') { + return; + } + + const courseEnabled = await AddonCourseCompletion.isPluginViewEnabledForCourse(instanceId); + if (!courseEnabled) { + return; + } + return { title: 'addon.block_completionstatus.pluginname', class: 'addon-block-completion-status', diff --git a/src/addons/block/selfcompletion/services/block-handler.ts b/src/addons/block/selfcompletion/services/block-handler.ts index 01bed3b35..2d82fe4c0 100644 --- a/src/addons/block/selfcompletion/services/block-handler.ts +++ b/src/addons/block/selfcompletion/services/block-handler.ts @@ -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 { + return AddonCourseCompletion.isCompletionEnabledInSite(); + } + + /** + * @inheritdoc + */ + async getDisplayData( + block: CoreCourseBlock, + contextLevel: string, + instanceId: number, + ): Promise { + if (contextLevel !== 'course') { + return; + } + + const courseEnabled = await AddonCourseCompletion.isPluginViewEnabledForCourse(instanceId); + if (!courseEnabled) { + return; + } + return { title: 'addon.block_selfcompletion.pluginname', class: 'addon-block-self-completion', diff --git a/src/addons/coursecompletion/services/coursecompletion.ts b/src/addons/coursecompletion/services/coursecompletion.ts index 44c1e1e5f..02de42577 100644 --- a/src/addons/coursecompletion/services/coursecompletion.ts +++ b/src/addons/coursecompletion/services/coursecompletion.ts @@ -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 { - if (!courseId) { + async isPluginViewEnabledForCourse(courseId?: number, preferCache = true): Promise { + 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; } /** diff --git a/src/addons/coursecompletion/tests/behat/navigation.feature b/src/addons/coursecompletion/tests/behat/navigation.feature new file mode 100644 index 000000000..7d8969f16 --- /dev/null +++ b/src/addons/coursecompletion/tests/behat/navigation.feature @@ -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 diff --git a/src/core/features/course/components/course-index/course-index.ts b/src/core/features/course/components/course-index/course-index.ts index cafce1827..a67118fde 100644 --- a/src/core/features/course/components/course-index/course-index.ts +++ b/src/core/features/course/components/course-index/course-index.ts @@ -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; } diff --git a/src/core/features/course/pages/contents/contents.ts b/src/core/features/course/pages/contents/contents.ts index ba640a94f..950a509c3 100644 --- a/src/core/features/course/pages/contents/contents.ts +++ b/src/core/features/course/pages/contents/contents.ts @@ -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 = {}; // 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 { // 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; } diff --git a/src/core/features/courses/services/courses-helper.ts b/src/core/features/courses/services/courses-helper.ts index 0c19e83ea..b066d129a 100644 --- a/src/core/features/courses/services/courses-helper.ts +++ b/src/core/features/courses/services/courses-helper.ts @@ -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); From 65ed0d2b1c9f7cd00d0b1826dab496354effd15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 28 Feb 2024 16:07:39 +0100 Subject: [PATCH 3/8] MOBILE-4498 blog: Use advanced features to check if blog is enabled --- src/addons/block/blogmenu/services/block-handler.ts | 8 ++++++++ src/addons/block/blogrecent/services/block-handler.ts | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/addons/block/blogmenu/services/block-handler.ts b/src/addons/block/blogmenu/services/block-handler.ts index dfe0aa3ee..45103da25 100644 --- a/src/addons/block/blogmenu/services/block-handler.ts +++ b/src/addons/block/blogmenu/services/block-handler.ts @@ -18,6 +18,7 @@ import { CoreBlockHandlerData } from '@features/block/services/block-delegate'; import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler'; import { AddonBlockBlogMenuComponent } from '../components/blogmenu/blogmenu'; import { makeSingleton } from '@singletons'; +import { AddonBlog } from '@addons/blog/services/blog'; /** * Block handler. @@ -28,6 +29,13 @@ export class AddonBlockBlogMenuHandlerService extends CoreBlockBaseHandler { name = 'AddonBlockBlogMenu'; blockName = 'blog_menu'; + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return await AddonBlog.isPluginEnabled(); + } + /** * Returns the data needed to render the block. * diff --git a/src/addons/block/blogrecent/services/block-handler.ts b/src/addons/block/blogrecent/services/block-handler.ts index 18d6f5e3b..1404c6db6 100644 --- a/src/addons/block/blogrecent/services/block-handler.ts +++ b/src/addons/block/blogrecent/services/block-handler.ts @@ -18,6 +18,7 @@ import { CoreBlockHandlerData } from '@features/block/services/block-delegate'; import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler'; import { AddonBlockBlogRecentComponent } from '../components/blogrecent/blogrecent'; import { makeSingleton } from '@singletons'; +import { AddonBlog } from '@addons/blog/services/blog'; /** * Block handler. @@ -28,6 +29,13 @@ export class AddonBlockBlogRecentHandlerService extends CoreBlockBaseHandler { name = 'AddonBlockBlogRecent'; blockName = 'blog_recent'; + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return await AddonBlog.isPluginEnabled(); + } + /** * Returns the data needed to render the block. * From 6a52b02eeb307eb675c1d24edd4e213b7ad0cb95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 28 Feb 2024 16:17:57 +0100 Subject: [PATCH 4/8] MOBILE-4498 comments: Use advanced features to check if comments are on --- .../block/comments/services/block-handler.ts | 8 ++++ src/addons/blog/pages/entries/entries.ts | 2 +- .../submission/comments/component/comments.ts | 2 +- src/addons/mod/data/pages/entry/entry.ts | 2 +- .../mod/data/services/handlers/prefetch.ts | 2 +- .../mod/data/tests/behat/entries.feature | 28 ++++++++++++-- src/addons/mod/glossary/pages/entry/entry.ts | 2 +- .../glossary/services/handlers/prefetch.ts | 2 +- .../comments/components/comments/comments.ts | 20 +++++----- .../components/comments/core-comments.html | 2 +- .../features/comments/services/comments.ts | 38 ++++++++++++++++--- 11 files changed, 81 insertions(+), 27 deletions(-) diff --git a/src/addons/block/comments/services/block-handler.ts b/src/addons/block/comments/services/block-handler.ts index 7ca6c2ef1..8a77ac7a4 100644 --- a/src/addons/block/comments/services/block-handler.ts +++ b/src/addons/block/comments/services/block-handler.ts @@ -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 { CoreComments } from '@features/comments/services/comments'; /** * Block handler. @@ -28,6 +29,13 @@ export class AddonBlockCommentsHandlerService extends CoreBlockBaseHandler { name = 'AddonBlockComments'; blockName = 'comments'; + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return await CoreComments.areCommentsEnabled(); + } + /** * Returns the data needed to render the block. * diff --git a/src/addons/blog/pages/entries/entries.ts b/src/addons/blog/pages/entries/entries.ts index a570d0786..3441163a0 100644 --- a/src/addons/blog/pages/entries/entries.ts +++ b/src/addons/blog/pages/entries/entries.ts @@ -139,7 +139,7 @@ export class AddonBlogEntriesPage implements OnInit { this.contextInstanceId = 0; } - this.commentsEnabled = !CoreComments.areCommentsDisabledInSite(); + this.commentsEnabled = CoreComments.areCommentsEnabledInSite(); this.tagsEnabled = CoreTag.areTagsAvailableInSite(); const deepLinkManager = new CoreMainMenuDeepLinkManager(); diff --git a/src/addons/mod/assign/submission/comments/component/comments.ts b/src/addons/mod/assign/submission/comments/component/comments.ts index 1488aa159..46cfe5861 100644 --- a/src/addons/mod/assign/submission/comments/component/comments.ts +++ b/src/addons/mod/assign/submission/comments/component/comments.ts @@ -33,7 +33,7 @@ export class AddonModAssignSubmissionCommentsComponent extends AddonModAssignSub constructor() { super(); - this.commentsEnabled = !CoreComments.areCommentsDisabledInSite(); + this.commentsEnabled = CoreComments.areCommentsEnabledInSite(); } /** diff --git a/src/addons/mod/data/pages/entry/entry.ts b/src/addons/mod/data/pages/entry/entry.ts index c8bd10562..1c46e26ef 100644 --- a/src/addons/mod/data/pages/entry/entry.ts +++ b/src/addons/mod/data/pages/entry/entry.ts @@ -157,7 +157,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy { return; } - this.commentsEnabled = !CoreComments.areCommentsDisabledInSite(); + this.commentsEnabled = CoreComments.areCommentsEnabledInSite(); await this.fetchEntryData(); } diff --git a/src/addons/mod/data/services/handlers/prefetch.ts b/src/addons/mod/data/services/handlers/prefetch.ts index 49a2027a8..c8a33a75c 100644 --- a/src/addons/mod/data/services/handlers/prefetch.ts +++ b/src/addons/mod/data/services/handlers/prefetch.ts @@ -230,7 +230,7 @@ export class AddonModDataPrefetchHandlerService extends CoreCourseActivityPrefet // Prefetch the database data. const database = info.database; - const commentsEnabled = !CoreComments.areCommentsDisabledInSite(); + const commentsEnabled = CoreComments.areCommentsEnabledInSite(); const promises: Promise[] = []; diff --git a/src/addons/mod/data/tests/behat/entries.feature b/src/addons/mod/data/tests/behat/entries.feature index dff57b440..e1f6f993f 100644 --- a/src/addons/mod/data/tests/behat/entries.feature +++ b/src/addons/mod/data/tests/behat/entries.feature @@ -19,8 +19,8 @@ Feature: Users can manage entries in database activities | student1 | C1 | student | | student2 | C1 | student | And the following "activities" exist: - | activity | name | intro | course | idnumber | - | data | Web links | Useful links | C1 | data1 | + | activity | name | intro | course | idnumber | comments | + | data | Web links | Useful links | C1 | data1 | 0 | And the following "mod_data > fields" exist: | database | type | name | description | | data1 | text | URL | URL link | @@ -38,7 +38,13 @@ Feature: Users can manage entries in database activities And I should find "Moodle community site" in the app Scenario: Browse entry - Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app + Given the following "activities" exist: + | activity | name | intro | course | idnumber | comments | + | data | Data with comments | - | C1 | data2 | 1 | + And the following "mod_data > fields" exist: + | database | type | name | description | + | data2 | text | Description | Description | + And I entered the data activity "Web links" on course "Course 1" as "student1" in the app # TODO Create and use a generator for database entries. When I press "Add entries" in the app @@ -54,6 +60,7 @@ Feature: Users can manage entries in database activities And I press "Save" near "Web links" in the app And I press "Show more" near "Moodle community site" in the app Then I should find "Moodle community site" in the app + And I should not find "Comments" in the app And I should be able to press "Previous" in the app But I should not be able to press "Next" in the app @@ -70,6 +77,21 @@ Feature: Users can manage entries in database activities And I should find "Moodle community site" in the app And I should find "Moodle Cloud" in the app + Given I entered the data activity "Data with comments" on course "Course 1" as "student1" in the app + When I press "Add entries" in the app + And I set the following fields to these values in the app: + | Description | Moodle community site | + And I press "Save" near "Data with comments" in the app + And I press "Show more" near "Moodle community site" in the app + Then I should find "Moodle community site" in the app + And I should find "Comments" in the app + + Given the following config values are set as admin: + | usecomments | 0 | + And I entered the data activity "Data with comments" on course "Course 1" as "student1" in the app + When I press "Show more" near "Moodle community site" in the app + Then I should not find "Comments" in the app + Scenario: Students can not edit or delete other user's entries from list and single view in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app And I press "Add entries" in the app diff --git a/src/addons/mod/glossary/pages/entry/entry.ts b/src/addons/mod/glossary/pages/entry/entry.ts index 3160c1818..f4b946f77 100644 --- a/src/addons/mod/glossary/pages/entry/entry.ts +++ b/src/addons/mod/glossary/pages/entry/entry.ts @@ -99,7 +99,7 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy { try { this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId'); this.tagsEnabled = CoreTag.areTagsAvailableInSite(); - this.commentsEnabled = !CoreComments.areCommentsDisabledInSite(); + this.commentsEnabled = CoreComments.areCommentsEnabledInSite(); this.cmId = CoreNavigator.getRequiredRouteNumberParam('cmId'); const entrySlug = CoreNavigator.getRequiredRouteParam('entrySlug'); diff --git a/src/addons/mod/glossary/services/handlers/prefetch.ts b/src/addons/mod/glossary/services/handlers/prefetch.ts index f9566bd0e..08690f68c 100644 --- a/src/addons/mod/glossary/services/handlers/prefetch.ts +++ b/src/addons/mod/glossary/services/handlers/prefetch.ts @@ -155,7 +155,7 @@ export class AddonModGlossaryPrefetchHandlerService extends CoreCourseActivityPr options, ).then((entries) => { const promises: Promise[] = []; - const commentsEnabled = !CoreComments.areCommentsDisabledInSite(); + const commentsEnabled = CoreComments.areCommentsEnabledInSite(); entries.forEach((entry) => { // Don't fetch individual entries, it's too many WS calls. diff --git a/src/core/features/comments/components/comments/comments.ts b/src/core/features/comments/components/comments/comments.ts index 26fed4370..31b1f85f9 100644 --- a/src/core/features/comments/components/comments/comments.ts +++ b/src/core/features/comments/components/comments/comments.ts @@ -45,7 +45,7 @@ export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestr commentsLoaded = false; commentsCount = ''; countError = false; - disabled = false; + enabled = false; protected updateSiteObserver?: CoreEventObserver; protected refreshCommentsObserver?: CoreEventObserver; @@ -55,15 +55,15 @@ export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestr this.onLoading = new EventEmitter(); - this.disabled = CoreComments.areCommentsDisabledInSite(); + this.enabled = CoreComments.areCommentsEnabledInSite(); // Update visibility if current site info is updated. this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => { - const wasDisabled = this.disabled; + const wasEnabled = this.enabled; - this.disabled = CoreComments.areCommentsDisabledInSite(); + this.enabled = CoreComments.areCommentsEnabledInSite(); - if (wasDisabled && !this.disabled) { + if (!wasEnabled && this.enabled) { this.fetchData(); } }, CoreSites.getCurrentSiteId()); @@ -123,7 +123,7 @@ export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestr * Fetch comments data. */ async fetchData(): Promise { - if (this.disabled) { + if (!this.enabled) { return; } @@ -173,12 +173,10 @@ export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestr * Opens the comments page. */ openComments(e?: Event): void { - if (e) { - e.preventDefault(); - e.stopPropagation(); - } + e?.preventDefault(); + e?.stopPropagation(); - if (this.disabled || this.countError) { + if (!this.enabled || this.countError) { return; } diff --git a/src/core/features/comments/components/comments/core-comments.html b/src/core/features/comments/components/comments/core-comments.html index 0eb566d94..a09077f48 100644 --- a/src/core/features/comments/components/comments/core-comments.html +++ b/src/core/features/comments/components/comments/core-comments.html @@ -1,4 +1,4 @@ - +