diff --git a/src/core/features/courses/services/handlers/course-link.ts b/src/core/features/courses/services/handlers/course-link.ts index 7b3d944d4..dfe5426a7 100644 --- a/src/core/features/courses/services/handlers/course-link.ts +++ b/src/core/features/courses/services/handlers/course-link.ts @@ -90,7 +90,7 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler return; } else { - this.actionEnrol(courseId, url, pageParams).catch(() => { + this.actionOpen(courseId, url, pageParams).catch(() => { // Ignore errors. }); } @@ -124,14 +124,14 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler } /** - * Action to perform when an enrol link is clicked. + * Try to open the course, asking the user to enrol if needed. * * @param courseId Course ID. * @param url Treated URL. * @param pageParams Params to send to the new page. * @return Promise resolved when done. */ - protected async actionEnrol(courseId: number, url: string, pageParams: Params): Promise { + protected async actionOpen(courseId: number, url: string, pageParams: Params): Promise { const modal = await CoreDomUtils.showModalLoading(); let course: CoreCourseAnyCourseData | { id: number } | undefined; @@ -167,95 +167,102 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler * @param modal Modal, to dismiss when needed. * @return The course after self enrolling or undefined if the user has access but is not enrolled. */ - protected checkSelfUserCanSelfEnrolOrAccess( + protected async checkSelfUserCanSelfEnrolOrAccess( courseId: number, url: string, modal: CoreIonLoadingElement, ): Promise { - // User is not enrolled in the course. Check if can self enrol. - return this.canSelfEnrol(courseId).then(async () => { - modal.dismiss(); + const isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/); - const isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/); + if (!isEnrolUrl) { + // Not an enrol URL, check if the user can access the course (e.g. guest access). + const canAccess = await this.canAccess(courseId); + if (canAccess) { + return; + } + } - // The user can self enrol. If it's not a enrolment URL we'll ask for confirmation. - if (!isEnrolUrl) { - try { - await CoreDomUtils.showConfirm(Translate.instant('core.courses.confirmselfenrol')); - } catch { - // User cancelled. Check if the user can view the course contents (guest access or similar). - await CoreCourse.getSections(courseId, false, true); + // User cannot access the course or it's an enrol URL. Check if can self enrol. + const canSelfEnrol = await this.canSelfEnrol(courseId); + if (!canSelfEnrol) { + if (isEnrolUrl) { + // Cannot self enrol, check if the user can access the course (e.g. guest access). + const canAccess = await this.canAccess(courseId); + if (canAccess) { return; } } - // Enrol URL or user confirmed. - try { - return this.selfEnrol(courseId); - } catch (error) { - if (error) { - CoreDomUtils.showErrorModal(error); - } + // Cannot self enrol and cannot access. Show error and allow the user to open the link in browser. + modal.dismiss(); + const notEnrolledMessage = Translate.instant('core.courses.notenroled'); + const body = CoreTextUtils.buildSeveralParagraphsMessage( + [notEnrolledMessage, Translate.instant('core.confirmopeninbrowser')], + ); - throw error; - } - }, async (error) => { - // Can't self enrol. Check if the user can view the course contents (guest access or similar). try { - await CoreCourse.getSections(courseId, false, true); + await CoreDomUtils.showConfirm(body); + + CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(url, undefined, { showBrowserWarning: false }); } catch { - // Error. Show error message and allow the user to open the link in browser. - modal.dismiss(); + // User cancelled. + }; - if (error) { - error = CoreTextUtils.getErrorMessageFromError(error) || error; - } - if (!error) { - error = Translate.instant('core.courses.notenroled'); - } + throw new CoreError(notEnrolledMessage); + } - const body = CoreTextUtils.buildSeveralParagraphsMessage( - [error, Translate.instant('core.confirmopeninbrowser')], - ); + // The user can self enrol. If it's not a enrolment URL we'll ask for confirmation. + modal.dismiss(); - try { - await CoreDomUtils.showConfirm(body); + if (!isEnrolUrl) { + await CoreDomUtils.showConfirm(Translate.instant('core.courses.confirmselfenrol')); + } - CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(url, undefined, { showBrowserWarning: false }); - } catch { - // User cancelled. - }; - - throw error; + try { + return await this.selfEnrol(courseId); + } catch (error) { + if (error) { + CoreDomUtils.showErrorModal(error); } - return undefined; - }); + throw error; + } + } + + /** + * Check if user can access the course. + * + * @param courseId Course ID. + * @return Promise resolved with boolean: whether user can access the course. + */ + protected canAccess(courseId: number): Promise { + return CoreUtils.promiseWorks(CoreCourse.getSections(courseId, false, true)); } /** * Check if a user can be "automatically" self enrolled in a course. * * @param courseId Course ID. - * @return Promise resolved if user can be enrolled in a course, rejected otherwise. + * @return Promise resolved with boolean: whether the user can be enrolled in a course. */ - protected async canSelfEnrol(courseId: number): Promise { - // Check that the course has self enrolment enabled. + protected async canSelfEnrol(courseId: number): Promise { + try { + // Check that the course has self enrolment enabled. + const methods = await CoreCourses.getCourseEnrolmentMethods(courseId); - const methods = await CoreCourses.getCourseEnrolmentMethods(courseId); - let isSelfEnrolEnabled = false; - let instances = 0; - methods.forEach((method) => { - if (method.type == 'self' && method.status) { - isSelfEnrolEnabled = true; - instances++; - } - }); + let isSelfEnrolEnabled = false; + let instances = 0; + methods.forEach((method) => { + if (method.type == 'self' && method.status) { + isSelfEnrolEnabled = true; + instances++; + } + }); - if (!isSelfEnrolEnabled || instances != 1) { - // Self enrol not enabled or more than one instance. - throw new CoreError('Self enrol not enabled in course'); + return isSelfEnrolEnabled && instances === 1; + } catch { + return false; } } @@ -272,12 +279,9 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler try { await CoreCourses.selfEnrol(courseId, password); - // Success self enrolling the user, invalidate the courses list. - await CoreUtils.ignoreErrors(CoreCourses.invalidateUserCourses()); - try { // Sometimes the list of enrolled courses takes a while to be updated. Wait for it. - return this.waitForEnrolled(courseId, true); + return await this.waitForEnrolled(courseId, true); } finally { modal.dismiss(); } @@ -297,7 +301,7 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler password = await CoreDomUtils.showPrompt(body, title, placeholder); - return this.selfEnrol(courseId, password); + await this.selfEnrol(courseId, password); } else { throw error; } @@ -319,21 +323,17 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler // Check if user is enrolled in the course. await CoreUtils.ignoreErrors(CoreCourses.invalidateUserCourses()); try { - return CoreCourses.getUserCourse(courseId); + return await CoreCourses.getUserCourse(courseId); } catch { - // Not enrolled, wait a bit and try again. if (Date.now() - this.waitStart > 60000) { // Max time reached, stop. return; } - return new Promise((resolve, reject): void => { - setTimeout(() => { - this.waitForEnrolled(courseId) - .then(resolve).catch(reject); - }, 5000); - }); + await CoreUtils.wait(5000); + + return await this.waitForEnrolled(courseId); } }