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