From 9038e883e7889951f51786aac3d586146692b16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 22 Mar 2024 12:04:23 +0100 Subject: [PATCH] MOBILE-4543 course: Do not show open in browser for students --- .../tests/behat/basic_usage.feature | 7 +-- .../tests/behat/basic_usage-311.feature | 6 +-- .../choice/tests/behat/basic_usage.feature | 6 +-- .../quiz/tests/behat/basic-usage-403.feature | 9 ++-- .../quiz/tests/behat/basic_usage-311.feature | 7 +-- .../mod/quiz/tests/behat/basic_usage.feature | 9 ++-- .../mod/scorm/tests/behat/basic_usage.feature | 3 +- .../module-summary/module-summary.html | 3 +- .../module-summary/module-summary.scss | 4 ++ .../module-summary/module-summary.ts | 4 +- .../pages/course-summary/course-summary.html | 3 +- .../course-summary/course-summary.page.ts | 4 ++ .../pages/course-summary/course-summary.scss | 4 ++ .../features/course/services/course-helper.ts | 24 +++++++++ .../tests/behat/basic_usage-311.feature | 13 +---- .../course/tests/behat/guest_access.feature | 6 +-- src/core/features/courses/services/courses.ts | 54 ++++++++++--------- .../behat/navigation_externallinks.feature | 8 +-- 18 files changed, 96 insertions(+), 78 deletions(-) diff --git a/src/addons/mod/bigbluebuttonbn/tests/behat/basic_usage.feature b/src/addons/mod/bigbluebuttonbn/tests/behat/basic_usage.feature index c36b00e19..b729cad8d 100755 --- a/src/addons/mod/bigbluebuttonbn/tests/behat/basic_usage.feature +++ b/src/addons/mod/bigbluebuttonbn/tests/behat/basic_usage.feature @@ -79,14 +79,11 @@ Feature: Test basic usage of BBB activity in app And I should not be able to press "Join session" in the app # Join the session as moderator in a browser. - When I press "Information" in the app - And I press "Open in browser" in the app - And I switch to the browser tab opened by the app - And I log in as "teacher1" + When I open a browser tab with url "$WWWROOT" + And I am on the "bbb1" Activity page logged in as teacher1 And I click on "Join session" "link" And I wait for the BigBlueButton room to start And I switch back to the app - And I press "Close" in the app And I pull to refresh until I find "The session is in progress" in the app Then I should find "1" near "Moderator" in the app And I should find "0" near "Viewer" in the app diff --git a/src/addons/mod/choice/tests/behat/basic_usage-311.feature b/src/addons/mod/choice/tests/behat/basic_usage-311.feature index 384c23688..a3ac822cd 100755 --- a/src/addons/mod/choice/tests/behat/basic_usage-311.feature +++ b/src/addons/mod/choice/tests/behat/basic_usage-311.feature @@ -31,10 +31,8 @@ Feature: Test basic usage of choice activity in app Given I entered the choice activity "Choice name" on course "Course 1" as "teacher1" in the app Then I should find "Test choice description" in the app - When I press "Information" in the app - And I press "Open in browser" in the app - And I switch to the browser tab opened by the app - And I log in as "teacher1" + When I open a browser tab with url "$WWWROOT" + And I am on the "choice1" Activity page logged in as teacher1 And I press "Actions menu" And I follow "View 1 responses" And I press "Download in text format" diff --git a/src/addons/mod/choice/tests/behat/basic_usage.feature b/src/addons/mod/choice/tests/behat/basic_usage.feature index 8ca30dfe3..3ce75d8d9 100755 --- a/src/addons/mod/choice/tests/behat/basic_usage.feature +++ b/src/addons/mod/choice/tests/behat/basic_usage.feature @@ -176,10 +176,8 @@ Feature: Test basic usage of choice activity in app Given I entered the choice activity "Choice name" on course "Course 1" as "teacher1" in the app Then I should find "Test choice description" in the app - When I press "Information" in the app - And I press "Open in browser" in the app - And I switch to the browser tab opened by the app - And I log in as "teacher1" + When I open a browser tab with url "$WWWROOT" + And I am on the "choice1" Activity page logged in as teacher1 And I follow "Responses" And I press "Download in text format" # TODO Then I should find "..." in the downloads folder diff --git a/src/addons/mod/quiz/tests/behat/basic-usage-403.feature b/src/addons/mod/quiz/tests/behat/basic-usage-403.feature index 65d70f103..1ed062922 100644 --- a/src/addons/mod/quiz/tests/behat/basic-usage-403.feature +++ b/src/addons/mod/quiz/tests/behat/basic-usage-403.feature @@ -207,12 +207,9 @@ Feature: Attempt a quiz in app And I replace "/.*/" within "page-addon-mod-quiz-review core-loading > ion-card ion-item:nth-child(3) p:nth-child(2)" with "[Completed on date]" Then the UI should match the snapshot - Given I entered the quiz activity "Quiz 1" on course "Course 1" as "teacher1" in the app - When I press "Information" in the app - And I press "Open in browser" in the app - And I switch to the browser tab opened by the app - And I log in as "teacher1" - And I follow "Attempts: 1" + Given I open a browser tab with url "$WWWROOT" + And I am on the "quiz1" Activity page logged in as teacher1 + When I follow "Attempts: 1" And I follow "Review attempt" Then I should see "Finished" And I should see "1.00/2.00" diff --git a/src/addons/mod/quiz/tests/behat/basic_usage-311.feature b/src/addons/mod/quiz/tests/behat/basic_usage-311.feature index 2c06b3ce1..e04ec0fa6 100644 --- a/src/addons/mod/quiz/tests/behat/basic_usage-311.feature +++ b/src/addons/mod/quiz/tests/behat/basic_usage-311.feature @@ -206,11 +206,8 @@ Feature: Attempt a quiz in app When I replace "/.*/" within "page-addon-mod-quiz-review core-loading > ion-card ion-item:nth-child(1) p:nth-child(2)" with "[Started on date]" And I replace "/.*/" within "page-addon-mod-quiz-review core-loading > ion-card ion-item:nth-child(3) p:nth-child(2)" with "[Completed on date]" - Given I entered the quiz activity "Quiz 1" on course "Course 1" as "teacher1" in the app - When I press "Information" in the app - And I press "Open in browser" in the app - And I switch to the browser tab opened by the app - And I log in as "teacher1" + Given I open a browser tab with url "$WWWROOT" + When I am on the "quiz1" Activity page logged in as teacher1 And I follow "Attempts: 1" And I follow "Review attempt" Then I should see "Finished" diff --git a/src/addons/mod/quiz/tests/behat/basic_usage.feature b/src/addons/mod/quiz/tests/behat/basic_usage.feature index af30c5a58..8cf359115 100755 --- a/src/addons/mod/quiz/tests/behat/basic_usage.feature +++ b/src/addons/mod/quiz/tests/behat/basic_usage.feature @@ -211,12 +211,9 @@ Feature: Attempt a quiz in app And I replace "/.*/" within "page-addon-mod-quiz-review core-loading > ion-card ion-item:nth-child(3) p:nth-child(2)" with "[Completed on date]" Then the UI should match the snapshot - Given I entered the quiz activity "Quiz 1" on course "Course 1" as "teacher1" in the app - When I press "Information" in the app - And I press "Open in browser" in the app - And I switch to the browser tab opened by the app - And I log in as "teacher1" - And I follow "Attempts: 1" + Given I open a browser tab with url "$WWWROOT" + And I am on the "quiz1" Activity page logged in as teacher1 + When I follow "Attempts: 1" And I follow "Review attempt" Then I should see "Finished" And I should see "1.00/2.00" diff --git a/src/addons/mod/scorm/tests/behat/basic_usage.feature b/src/addons/mod/scorm/tests/behat/basic_usage.feature index b3316c8ef..9ed1be36b 100755 --- a/src/addons/mod/scorm/tests/behat/basic_usage.feature +++ b/src/addons/mod/scorm/tests/behat/basic_usage.feature @@ -233,8 +233,7 @@ Feature: Test basic usage of SCORM activity in app Then I should find "2 / 11" in the app When I open a browser tab with url "$WWWROOT" - And I log in as "admin" - And I am on the "System logs report" page + And I am on the "System logs report" page logged in as "admin" And I set the field "id" to "Course 1" And I set the field "user" to "Student student" And I press "Get these logs" diff --git a/src/core/features/course/components/module-summary/module-summary.html b/src/core/features/course/components/module-summary/module-summary.html index f1e8cdc70..3516aa08b 100644 --- a/src/core/features/course/components/module-summary/module-summary.html +++ b/src/core/features/course/components/module-summary/module-summary.html @@ -24,7 +24,8 @@ + [showBrowserWarning]="false" [attr.aria-label]="'core.openinbrowser' | translate" slot="end" [class.hidden]="!isTeacher" + class="core-module-oib-button"> diff --git a/src/core/features/course/components/module-summary/module-summary.scss b/src/core/features/course/components/module-summary/module-summary.scss index 6b2c74d6b..eaa2daebf 100644 --- a/src/core/features/course/components/module-summary/module-summary.scss +++ b/src/core/features/course/components/module-summary/module-summary.scss @@ -39,3 +39,7 @@ ion-item.card-header { margin: 0px; } } + +.core-module-oib-button.hidden { + display: none; +} diff --git a/src/core/features/course/components/module-summary/module-summary.ts b/src/core/features/course/components/module-summary/module-summary.ts index 42d3b28b0..669400790 100644 --- a/src/core/features/course/components/module-summary/module-summary.ts +++ b/src/core/features/course/components/module-summary/module-summary.ts @@ -70,6 +70,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { course?: CoreEnrolledCourseData; modicon = ''; moduleNameTranslated = ''; + isTeacher = false; protected onlineSubscription: Subscription; // It will observe the status of the network connection. protected packageStatusObserver?: CoreEventObserver; // Observer of package status. @@ -269,13 +270,14 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { * Fetch course. */ protected async fetchCourse(): Promise { - // Fix that. try { this.course = await CoreCourses.getUserCourse(this.courseId, true); } catch { // The user is not enrolled in the course. Use getCourses to see if it's an admin/manager and can see the course. this.course = await CoreCourses.getCourse(this.courseId); } + + this.isTeacher = await CoreUtils.ignoreErrors(CoreCourseHelper.guessIsTeacher(this.courseId, this.course), false); } /** diff --git a/src/core/features/course/pages/course-summary/course-summary.html b/src/core/features/course/pages/course-summary/course-summary.html index bf8bd280a..7902ac903 100644 --- a/src/core/features/course/pages/course-summary/course-summary.html +++ b/src/core/features/course/pages/course-summary/course-summary.html @@ -41,7 +41,8 @@ + [attr.aria-label]="'core.openinbrowser' | translate" slot="end" [class.hidden]="!isTeacher" + class="core-course-oib-button"> diff --git a/src/core/features/course/pages/course-summary/course-summary.page.ts b/src/core/features/course/pages/course-summary/course-summary.page.ts index 0572a7f7d..0f7145a5f 100644 --- a/src/core/features/course/pages/course-summary/course-summary.page.ts +++ b/src/core/features/course/pages/course-summary/course-summary.page.ts @@ -73,6 +73,7 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { progress?: number; courseMenuHandlers: CoreCourseOptionsMenuHandlerToDisplay[] = []; displayOpenInBrowser = false; + isTeacher = false; protected actionSheet?: HTMLIonActionSheetElement; protected waitStart = 0; @@ -172,6 +173,9 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { await this.loadMenuHandlers(refresh); + // After loading menu handlers, admOptions should be available. + this.isTeacher = await CoreUtils.ignoreErrors(CoreCourseHelper.guessIsTeacher(this.courseId, this.course), false); + this.dataLoaded = true; } diff --git a/src/core/features/course/pages/course-summary/course-summary.scss b/src/core/features/course/pages/course-summary/course-summary.scss index 65aa299b5..ac0aecbaf 100644 --- a/src/core/features/course/pages/course-summary/course-summary.scss +++ b/src/core/features/course/pages/course-summary/course-summary.scss @@ -104,4 +104,8 @@ display: inline; } } + + .core-course-oib-button.hidden { + display: none; + } } diff --git a/src/core/features/course/services/course-helper.ts b/src/core/features/course/services/course-helper.ts index a20f2b735..0b770a84d 100644 --- a/src/core/features/course/services/course-helper.ts +++ b/src/core/features/course/services/course-helper.ts @@ -2058,6 +2058,30 @@ export class CoreCourseHelperProvider { } } + /** + * Guess if the user is a teacher in a course. + * + * @param courseId Course Id. + * @param course Course object. + * @returns Promise resolved with boolean: whether the user is a teacher. + */ + async guessIsTeacher( + courseId: number, + course?: CoreEnrolledCourseData | CoreCourseSearchedData, + ): Promise { + if (course && 'admOptions' in course && course.admOptions) { + return !!course.admOptions['reports']; + } + + // Not loaded yet, try to load it. + const adminOptions = await CoreCourses.getUserAdministrationOptions( + [courseId], + { readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE }, + ); + + return !!adminOptions[courseId]?.['reports']; + } + } export const CoreCourseHelper = makeSingleton(CoreCourseHelperProvider); diff --git a/src/core/features/course/tests/behat/basic_usage-311.feature b/src/core/features/course/tests/behat/basic_usage-311.feature index 382a97e27..21e549608 100755 --- a/src/core/features/course/tests/behat/basic_usage-311.feature +++ b/src/core/features/course/tests/behat/basic_usage-311.feature @@ -101,18 +101,9 @@ Feature: Test basic usage of one course in app And I should not find "Test glossary" in the app Scenario: Guest access - Given I entered the course "Course 1" as "teacher1" in the app - And I press "Course summary" in the app - And I press "Open in browser" in the app - And I switch to the browser tab opened by the app - And I log in as "teacher1" - And I press "Actions menu" - And I follow "More..." - And I follow "Users" - And I follow "Enrolment methods" + Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1" And I click on "Enable" "icon" in the "Guest access" "table_row" - And I close the browser tab opened by the app - Given I entered the app as "student2" + And I entered the app as "student2" When I press "Site home" in the app And I press "Available courses" in the app And I press "Course 1" in the app diff --git a/src/core/features/course/tests/behat/guest_access.feature b/src/core/features/course/tests/behat/guest_access.feature index c9ebafcc9..c6271f94c 100644 --- a/src/core/features/course/tests/behat/guest_access.feature +++ b/src/core/features/course/tests/behat/guest_access.feature @@ -23,8 +23,7 @@ Feature: Test basic usage of guest access course in app @lms_from4.0 Scenario: Guest access without password (student) - Given I log in as "teacher1" - And I am on the "Course 1" "enrolment methods" page + Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1" And I click on "Edit" "link" in the "Guest access" "table_row" And I set the following fields to these values: | Allow guest access | Yes | @@ -47,8 +46,7 @@ Feature: Test basic usage of guest access course in app @lms_from4.3 Scenario: Guest access with password (student) - Given I log in as "teacher1" - And I am on the "Course 1" "enrolment methods" page + Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1" And I click on "Edit" "link" in the "Guest access" "table_row" And I set the following fields to these values: | Allow guest access | Yes | diff --git a/src/core/features/courses/services/courses.ts b/src/core/features/courses/services/courses.ts index cf30f5e9d..b56755dab 100644 --- a/src/core/features/courses/services/courses.ts +++ b/src/core/features/courses/services/courses.ts @@ -27,8 +27,6 @@ import { AddonEnrolSelf } from '@addons/enrol/self/services/self'; import { CoreEnrol, CoreEnrolEnrolmentInfo, CoreEnrolEnrolmentMethod } from '@features/enrol/services/enrol'; import { CoreSiteWSPreSets, WSObservable } from '@classes/sites/authenticated-site'; -const ROOT_CACHE_KEY = 'mmCourses:'; - declare module '@singletons/events' { /** @@ -50,6 +48,8 @@ declare module '@singletons/events' { @Injectable({ providedIn: 'root' }) export class CoreCoursesProvider { + protected static readonly ROOT_CACHE_KEY = 'mmCourses:'; + static readonly SEARCH_PER_PAGE = 20; static readonly RECENT_PER_PAGE = 10; static readonly ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey'; @@ -114,7 +114,7 @@ export class CoreCoursesProvider { * @returns Cache key. */ protected getCategoriesCacheKey(categoryId: number, addSubcategories?: boolean): string { - return ROOT_CACHE_KEY + 'categories:' + categoryId + ':' + !!addSubcategories; + return `${CoreCoursesProvider.ROOT_CACHE_KEY}categories:${categoryId}:${!!addSubcategories}`; } /** @@ -131,16 +131,16 @@ export class CoreCoursesProvider { if (courseIds.length == 1) { // Only 1 course, check if it belongs to the user courses. If so, use all user courses. return this.getCourseIdsIfEnrolled(courseIds[0], siteId); - } else { - if (courseIds.length > 1 && courseIds.indexOf(siteHomeId) == -1) { - courseIds.push(siteHomeId); - } - - // Sort the course IDs. - courseIds.sort((a, b) => b - a); - - return courseIds; } + + if (courseIds.length > 1 && courseIds.indexOf(siteHomeId) == -1) { + courseIds.push(siteHomeId); + } + + // Sort the course IDs. + courseIds.sort((a, b) => b - a); + + return courseIds; } /** @@ -363,7 +363,7 @@ export class CoreCoursesProvider { * @returns Cache key. */ protected getCoursesCacheKey(ids: number[]): string { - return ROOT_CACHE_KEY + 'course:' + JSON.stringify(ids); + return `${CoreCoursesProvider.ROOT_CACHE_KEY}course:${JSON.stringify(ids)}`; } /** @@ -536,7 +536,7 @@ export class CoreCoursesProvider { * @returns Cache key. */ protected getCoursesByFieldCacheKey(field: string = '', value: string | number = ''): string { - return ROOT_CACHE_KEY + 'coursesbyfield:' + field + ':' + value; + return `${CoreCoursesProvider.ROOT_CACHE_KEY}coursesbyfield:${field}:${value}`; } /** @@ -651,7 +651,7 @@ export class CoreCoursesProvider { * @returns Cache key. */ protected getRecentCoursesCacheKey(userId: number): string { - return `${ROOT_CACHE_KEY}:recentcourses:${userId}`; + return `${CoreCoursesProvider.ROOT_CACHE_KEY}:recentcourses:${userId}`; } /** @@ -684,7 +684,7 @@ export class CoreCoursesProvider { * @returns Cache key. */ protected getUserAdministrationOptionsCommonCacheKey(): string { - return ROOT_CACHE_KEY + 'administrationOptions:'; + return `${CoreCoursesProvider.ROOT_CACHE_KEY}administrationOptions:`; } /** @@ -701,11 +701,14 @@ export class CoreCoursesProvider { * Get user administration options for a set of courses. * * @param courseIds IDs of courses to get. - * @param siteId Site ID. If not defined, current site. + * @param options Options. * @returns Promise resolved with administration options for each course. */ - getUserAdministrationOptions(courseIds: number[], siteId?: string): Promise { - return firstValueFrom(this.getUserAdministrationOptionsObservable(courseIds, { siteId })); + getUserAdministrationOptions( + courseIds: number[], + options?: CoreSitesCommonWSOptions, + ): Promise { + return firstValueFrom(this.getUserAdministrationOptionsObservable(courseIds, options)); } /** @@ -752,7 +755,7 @@ export class CoreCoursesProvider { * @returns Cache key. */ protected getUserNavigationOptionsCommonCacheKey(): string { - return ROOT_CACHE_KEY + 'navigationOptions:'; + return `${CoreCoursesProvider.ROOT_CACHE_KEY}navigationOptions:`; } /** @@ -768,11 +771,14 @@ export class CoreCoursesProvider { * Get user navigation options for a set of courses. * * @param courseIds IDs of courses to get. - * @param siteId Site ID. If not defined, current site. + * @param options Options. * @returns Promise resolved with navigation options for each course. */ - async getUserNavigationOptions(courseIds: number[], siteId?: string): Promise { - return firstValueFrom(this.getUserNavigationOptionsObservable(courseIds, { siteId })); + getUserNavigationOptions( + courseIds: number[], + options?: CoreSitesCommonWSOptions, + ): Promise { + return firstValueFrom(this.getUserNavigationOptionsObservable(courseIds, options)); } /** @@ -981,7 +987,7 @@ export class CoreCoursesProvider { * @returns Cache key. */ protected getUserCoursesCacheKey(): string { - return ROOT_CACHE_KEY + 'usercourses'; + return `${CoreCoursesProvider.ROOT_CACHE_KEY}usercourses`; } /** diff --git a/src/core/tests/behat/navigation_externallinks.feature b/src/core/tests/behat/navigation_externallinks.feature index 51eef475a..edfb96896 100644 --- a/src/core/tests/behat/navigation_externallinks.feature +++ b/src/core/tests/behat/navigation_externallinks.feature @@ -4,22 +4,22 @@ Feature: It opens external links properly. Background: Given the following "users" exist: | username | - | student1 | + | teacher1 | And the following "courses" exist: | fullname | shortname | | Course 1 | C1 | And the following "course enrolments" exist: | user | course | role | - | student1 | C1 | student | + | teacher1 | C1 | teacher | And the following "activities" exist: | activity | name | intro | course | idnumber | | forum | Test forum | Test forum | C1 | forum | And the following forum discussions exist in course "Course 1": | forum | user | name | message | - | Test forum | student1 | Forum topic | See moodle.org external link | + | Test forum | teacher1 | Forum topic | See moodle.org external link | Scenario: Click an external link - Given I entered the forum activity "Test forum" on course "Course 1" as "student1" in the app + Given I entered the forum activity "Test forum" on course "Course 1" as "teacher1" in the app When I press "Forum topic" in the app And I press "moodle.org external link" in the app Then I should find "You are about to leave the app" in the app