MOBILE-4543 course: Do not show open in browser for students
parent
4f56e08f9b
commit
9038e883e7
|
@ -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
|
And I should not be able to press "Join session" in the app
|
||||||
|
|
||||||
# Join the session as moderator in a browser.
|
# Join the session as moderator in a browser.
|
||||||
When I press "Information" in the app
|
When I open a browser tab with url "$WWWROOT"
|
||||||
And I press "Open in browser" in the app
|
And I am on the "bbb1" Activity page logged in as teacher1
|
||||||
And I switch to the browser tab opened by the app
|
|
||||||
And I log in as "teacher1"
|
|
||||||
And I click on "Join session" "link"
|
And I click on "Join session" "link"
|
||||||
And I wait for the BigBlueButton room to start
|
And I wait for the BigBlueButton room to start
|
||||||
And I switch back to the app
|
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
|
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
|
Then I should find "1" near "Moderator" in the app
|
||||||
And I should find "0" near "Viewer" in the app
|
And I should find "0" near "Viewer" in the app
|
||||||
|
|
|
@ -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
|
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
|
Then I should find "Test choice description" in the app
|
||||||
|
|
||||||
When I press "Information" in the app
|
When I open a browser tab with url "$WWWROOT"
|
||||||
And I press "Open in browser" in the app
|
And I am on the "choice1" Activity page logged in as teacher1
|
||||||
And I switch to the browser tab opened by the app
|
|
||||||
And I log in as "teacher1"
|
|
||||||
And I press "Actions menu"
|
And I press "Actions menu"
|
||||||
And I follow "View 1 responses"
|
And I follow "View 1 responses"
|
||||||
And I press "Download in text format"
|
And I press "Download in text format"
|
||||||
|
|
|
@ -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
|
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
|
Then I should find "Test choice description" in the app
|
||||||
|
|
||||||
When I press "Information" in the app
|
When I open a browser tab with url "$WWWROOT"
|
||||||
And I press "Open in browser" in the app
|
And I am on the "choice1" Activity page logged in as teacher1
|
||||||
And I switch to the browser tab opened by the app
|
|
||||||
And I log in as "teacher1"
|
|
||||||
And I follow "Responses"
|
And I follow "Responses"
|
||||||
And I press "Download in text format"
|
And I press "Download in text format"
|
||||||
# TODO Then I should find "..." in the downloads folder
|
# TODO Then I should find "..." in the downloads folder
|
||||||
|
|
|
@ -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]"
|
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
|
Then the UI should match the snapshot
|
||||||
|
|
||||||
Given I entered the quiz activity "Quiz 1" on course "Course 1" as "teacher1" in the app
|
Given I open a browser tab with url "$WWWROOT"
|
||||||
When I press "Information" in the app
|
And I am on the "quiz1" Activity page logged in as teacher1
|
||||||
And I press "Open in browser" in the app
|
When I follow "Attempts: 1"
|
||||||
And I switch to the browser tab opened by the app
|
|
||||||
And I log in as "teacher1"
|
|
||||||
And I follow "Attempts: 1"
|
|
||||||
And I follow "Review attempt"
|
And I follow "Review attempt"
|
||||||
Then I should see "Finished"
|
Then I should see "Finished"
|
||||||
And I should see "1.00/2.00"
|
And I should see "1.00/2.00"
|
||||||
|
|
|
@ -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]"
|
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]"
|
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
|
Given I open a browser tab with url "$WWWROOT"
|
||||||
When I press "Information" in the app
|
When I am on the "quiz1" Activity page logged in as teacher1
|
||||||
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"
|
And I follow "Attempts: 1"
|
||||||
And I follow "Review attempt"
|
And I follow "Review attempt"
|
||||||
Then I should see "Finished"
|
Then I should see "Finished"
|
||||||
|
|
|
@ -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]"
|
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
|
Then the UI should match the snapshot
|
||||||
|
|
||||||
Given I entered the quiz activity "Quiz 1" on course "Course 1" as "teacher1" in the app
|
Given I open a browser tab with url "$WWWROOT"
|
||||||
When I press "Information" in the app
|
And I am on the "quiz1" Activity page logged in as teacher1
|
||||||
And I press "Open in browser" in the app
|
When I follow "Attempts: 1"
|
||||||
And I switch to the browser tab opened by the app
|
|
||||||
And I log in as "teacher1"
|
|
||||||
And I follow "Attempts: 1"
|
|
||||||
And I follow "Review attempt"
|
And I follow "Review attempt"
|
||||||
Then I should see "Finished"
|
Then I should see "Finished"
|
||||||
And I should see "1.00/2.00"
|
And I should see "1.00/2.00"
|
||||||
|
|
|
@ -233,8 +233,7 @@ Feature: Test basic usage of SCORM activity in app
|
||||||
Then I should find "2 / 11" in the app
|
Then I should find "2 / 11" in the app
|
||||||
|
|
||||||
When I open a browser tab with url "$WWWROOT"
|
When I open a browser tab with url "$WWWROOT"
|
||||||
And I log in as "admin"
|
And I am on the "System logs report" page logged in as "admin"
|
||||||
And I am on the "System logs report" page
|
|
||||||
And I set the field "id" to "Course 1"
|
And I set the field "id" to "Course 1"
|
||||||
And I set the field "user" to "Student student"
|
And I set the field "user" to "Student student"
|
||||||
And I press "Get these logs"
|
And I press "Get these logs"
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
</h1>
|
</h1>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser && externalUrl" [href]="externalUrl" core-link
|
<ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser && externalUrl" [href]="externalUrl" core-link
|
||||||
[showBrowserWarning]="false" [attr.aria-label]="'core.openinbrowser' | translate" slot="end">
|
[showBrowserWarning]="false" [attr.aria-label]="'core.openinbrowser' | translate" slot="end" [class.hidden]="!isTeacher"
|
||||||
|
class="core-module-oib-button">
|
||||||
<ion-icon name="fas-up-right-from-square" slot="icon-only" aria-hidden="true" />
|
<ion-icon name="fas-up-right-from-square" slot="icon-only" aria-hidden="true" />
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -39,3 +39,7 @@ ion-item.card-header {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.core-module-oib-button.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy {
|
||||||
course?: CoreEnrolledCourseData;
|
course?: CoreEnrolledCourseData;
|
||||||
modicon = '';
|
modicon = '';
|
||||||
moduleNameTranslated = '';
|
moduleNameTranslated = '';
|
||||||
|
isTeacher = false;
|
||||||
|
|
||||||
protected onlineSubscription: Subscription; // It will observe the status of the network connection.
|
protected onlineSubscription: Subscription; // It will observe the status of the network connection.
|
||||||
protected packageStatusObserver?: CoreEventObserver; // Observer of package status.
|
protected packageStatusObserver?: CoreEventObserver; // Observer of package status.
|
||||||
|
@ -269,13 +270,14 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy {
|
||||||
* Fetch course.
|
* Fetch course.
|
||||||
*/
|
*/
|
||||||
protected async fetchCourse(): Promise<void> {
|
protected async fetchCourse(): Promise<void> {
|
||||||
// Fix that.
|
|
||||||
try {
|
try {
|
||||||
this.course = await CoreCourses.getUserCourse(this.courseId, true);
|
this.course = await CoreCourses.getUserCourse(this.courseId, true);
|
||||||
} catch {
|
} catch {
|
||||||
// The user is not enrolled in the course. Use getCourses to see if it's an admin/manager and can see the course.
|
// 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.course = await CoreCourses.getCourse(this.courseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isTeacher = await CoreUtils.ignoreErrors(CoreCourseHelper.guessIsTeacher(this.courseId, this.course), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -41,7 +41,8 @@
|
||||||
</ion-chip>
|
</ion-chip>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-button *ngIf="displayOpenInBrowser" fill="clear" [href]="courseUrl" core-link [showBrowserWarning]="false"
|
<ion-button *ngIf="displayOpenInBrowser" fill="clear" [href]="courseUrl" core-link [showBrowserWarning]="false"
|
||||||
[attr.aria-label]="'core.openinbrowser' | translate" slot="end">
|
[attr.aria-label]="'core.openinbrowser' | translate" slot="end" [class.hidden]="!isTeacher"
|
||||||
|
class="core-course-oib-button">
|
||||||
<ion-icon name="fas-up-right-from-square" slot="icon-only" aria-hidden="true" />
|
<ion-icon name="fas-up-right-from-square" slot="icon-only" aria-hidden="true" />
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -73,6 +73,7 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy {
|
||||||
progress?: number;
|
progress?: number;
|
||||||
courseMenuHandlers: CoreCourseOptionsMenuHandlerToDisplay[] = [];
|
courseMenuHandlers: CoreCourseOptionsMenuHandlerToDisplay[] = [];
|
||||||
displayOpenInBrowser = false;
|
displayOpenInBrowser = false;
|
||||||
|
isTeacher = false;
|
||||||
|
|
||||||
protected actionSheet?: HTMLIonActionSheetElement;
|
protected actionSheet?: HTMLIonActionSheetElement;
|
||||||
protected waitStart = 0;
|
protected waitStart = 0;
|
||||||
|
@ -172,6 +173,9 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
await this.loadMenuHandlers(refresh);
|
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;
|
this.dataLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,4 +104,8 @@
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.core-course-oib-button.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<boolean> {
|
||||||
|
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);
|
export const CoreCourseHelper = makeSingleton(CoreCourseHelperProvider);
|
||||||
|
|
|
@ -101,18 +101,9 @@ Feature: Test basic usage of one course in app
|
||||||
And I should not find "Test glossary" in the app
|
And I should not find "Test glossary" in the app
|
||||||
|
|
||||||
Scenario: Guest access
|
Scenario: Guest access
|
||||||
Given I entered the course "Course 1" as "teacher1" in the app
|
Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1"
|
||||||
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"
|
|
||||||
And I click on "Enable" "icon" in the "Guest access" "table_row"
|
And I click on "Enable" "icon" in the "Guest access" "table_row"
|
||||||
And I close the browser tab opened by the app
|
And I entered the app as "student2"
|
||||||
Given I entered the app as "student2"
|
|
||||||
When I press "Site home" in the app
|
When I press "Site home" in the app
|
||||||
And I press "Available courses" in the app
|
And I press "Available courses" in the app
|
||||||
And I press "Course 1" in the app
|
And I press "Course 1" in the app
|
||||||
|
|
|
@ -23,8 +23,7 @@ Feature: Test basic usage of guest access course in app
|
||||||
|
|
||||||
@lms_from4.0
|
@lms_from4.0
|
||||||
Scenario: Guest access without password (student)
|
Scenario: Guest access without password (student)
|
||||||
Given I log in as "teacher1"
|
Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1"
|
||||||
And I am on the "Course 1" "enrolment methods" page
|
|
||||||
And I click on "Edit" "link" in the "Guest access" "table_row"
|
And I click on "Edit" "link" in the "Guest access" "table_row"
|
||||||
And I set the following fields to these values:
|
And I set the following fields to these values:
|
||||||
| Allow guest access | Yes |
|
| Allow guest access | Yes |
|
||||||
|
@ -47,8 +46,7 @@ Feature: Test basic usage of guest access course in app
|
||||||
|
|
||||||
@lms_from4.3
|
@lms_from4.3
|
||||||
Scenario: Guest access with password (student)
|
Scenario: Guest access with password (student)
|
||||||
Given I log in as "teacher1"
|
Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1"
|
||||||
And I am on the "Course 1" "enrolment methods" page
|
|
||||||
And I click on "Edit" "link" in the "Guest access" "table_row"
|
And I click on "Edit" "link" in the "Guest access" "table_row"
|
||||||
And I set the following fields to these values:
|
And I set the following fields to these values:
|
||||||
| Allow guest access | Yes |
|
| Allow guest access | Yes |
|
||||||
|
|
|
@ -27,8 +27,6 @@ import { AddonEnrolSelf } from '@addons/enrol/self/services/self';
|
||||||
import { CoreEnrol, CoreEnrolEnrolmentInfo, CoreEnrolEnrolmentMethod } from '@features/enrol/services/enrol';
|
import { CoreEnrol, CoreEnrolEnrolmentInfo, CoreEnrolEnrolmentMethod } from '@features/enrol/services/enrol';
|
||||||
import { CoreSiteWSPreSets, WSObservable } from '@classes/sites/authenticated-site';
|
import { CoreSiteWSPreSets, WSObservable } from '@classes/sites/authenticated-site';
|
||||||
|
|
||||||
const ROOT_CACHE_KEY = 'mmCourses:';
|
|
||||||
|
|
||||||
declare module '@singletons/events' {
|
declare module '@singletons/events' {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,6 +48,8 @@ declare module '@singletons/events' {
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class CoreCoursesProvider {
|
export class CoreCoursesProvider {
|
||||||
|
|
||||||
|
protected static readonly ROOT_CACHE_KEY = 'mmCourses:';
|
||||||
|
|
||||||
static readonly SEARCH_PER_PAGE = 20;
|
static readonly SEARCH_PER_PAGE = 20;
|
||||||
static readonly RECENT_PER_PAGE = 10;
|
static readonly RECENT_PER_PAGE = 10;
|
||||||
static readonly ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
|
static readonly ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
|
||||||
|
@ -114,7 +114,7 @@ export class CoreCoursesProvider {
|
||||||
* @returns Cache key.
|
* @returns Cache key.
|
||||||
*/
|
*/
|
||||||
protected getCategoriesCacheKey(categoryId: number, addSubcategories?: boolean): string {
|
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) {
|
if (courseIds.length == 1) {
|
||||||
// Only 1 course, check if it belongs to the user courses. If so, use all user courses.
|
// Only 1 course, check if it belongs to the user courses. If so, use all user courses.
|
||||||
return this.getCourseIdsIfEnrolled(courseIds[0], siteId);
|
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.
|
* @returns Cache key.
|
||||||
*/
|
*/
|
||||||
protected getCoursesCacheKey(ids: number[]): string {
|
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.
|
* @returns Cache key.
|
||||||
*/
|
*/
|
||||||
protected getCoursesByFieldCacheKey(field: string = '', value: string | number = ''): string {
|
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.
|
* @returns Cache key.
|
||||||
*/
|
*/
|
||||||
protected getRecentCoursesCacheKey(userId: number): string {
|
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.
|
* @returns Cache key.
|
||||||
*/
|
*/
|
||||||
protected getUserAdministrationOptionsCommonCacheKey(): string {
|
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.
|
* Get user administration options for a set of courses.
|
||||||
*
|
*
|
||||||
* @param courseIds IDs of courses to get.
|
* @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.
|
* @returns Promise resolved with administration options for each course.
|
||||||
*/
|
*/
|
||||||
getUserAdministrationOptions(courseIds: number[], siteId?: string): Promise<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
getUserAdministrationOptions(
|
||||||
return firstValueFrom(this.getUserAdministrationOptionsObservable(courseIds, { siteId }));
|
courseIds: number[],
|
||||||
|
options?: CoreSitesCommonWSOptions,
|
||||||
|
): Promise<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
||||||
|
return firstValueFrom(this.getUserAdministrationOptionsObservable(courseIds, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -752,7 +755,7 @@ export class CoreCoursesProvider {
|
||||||
* @returns Cache key.
|
* @returns Cache key.
|
||||||
*/
|
*/
|
||||||
protected getUserNavigationOptionsCommonCacheKey(): string {
|
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.
|
* Get user navigation options for a set of courses.
|
||||||
*
|
*
|
||||||
* @param courseIds IDs of courses to get.
|
* @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.
|
* @returns Promise resolved with navigation options for each course.
|
||||||
*/
|
*/
|
||||||
async getUserNavigationOptions(courseIds: number[], siteId?: string): Promise<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
getUserNavigationOptions(
|
||||||
return firstValueFrom(this.getUserNavigationOptionsObservable(courseIds, { siteId }));
|
courseIds: number[],
|
||||||
|
options?: CoreSitesCommonWSOptions,
|
||||||
|
): Promise<CoreCourseUserAdminOrNavOptionCourseIndexed> {
|
||||||
|
return firstValueFrom(this.getUserNavigationOptionsObservable(courseIds, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -981,7 +987,7 @@ export class CoreCoursesProvider {
|
||||||
* @returns Cache key.
|
* @returns Cache key.
|
||||||
*/
|
*/
|
||||||
protected getUserCoursesCacheKey(): string {
|
protected getUserCoursesCacheKey(): string {
|
||||||
return ROOT_CACHE_KEY + 'usercourses';
|
return `${CoreCoursesProvider.ROOT_CACHE_KEY}usercourses`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,22 +4,22 @@ Feature: It opens external links properly.
|
||||||
Background:
|
Background:
|
||||||
Given the following "users" exist:
|
Given the following "users" exist:
|
||||||
| username |
|
| username |
|
||||||
| student1 |
|
| teacher1 |
|
||||||
And the following "courses" exist:
|
And the following "courses" exist:
|
||||||
| fullname | shortname |
|
| fullname | shortname |
|
||||||
| Course 1 | C1 |
|
| Course 1 | C1 |
|
||||||
And the following "course enrolments" exist:
|
And the following "course enrolments" exist:
|
||||||
| user | course | role |
|
| user | course | role |
|
||||||
| student1 | C1 | student |
|
| teacher1 | C1 | teacher |
|
||||||
And the following "activities" exist:
|
And the following "activities" exist:
|
||||||
| activity | name | intro | course | idnumber |
|
| activity | name | intro | course | idnumber |
|
||||||
| forum | Test forum | Test forum | C1 | forum |
|
| forum | Test forum | Test forum | C1 | forum |
|
||||||
And the following forum discussions exist in course "Course 1":
|
And the following forum discussions exist in course "Course 1":
|
||||||
| forum | user | name | message |
|
| forum | user | name | message |
|
||||||
| Test forum | student1 | Forum topic | See <a href="https://moodle.org/">moodle.org external link</a> |
|
| Test forum | teacher1 | Forum topic | See <a href="https://moodle.org/">moodle.org external link</a> |
|
||||||
|
|
||||||
Scenario: Click an 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
|
When I press "Forum topic" in the app
|
||||||
And I press "moodle.org external link" 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
|
Then I should find "You are about to leave the app" in the app
|
||||||
|
|
Loading…
Reference in New Issue