forked from EVOgeek/Vmeda.Online
		
	
						commit
						6f5b68be64
					
				| @ -39,7 +39,6 @@ import { CoreColors } from '@singletons/colors'; | ||||
| import { CorePath } from '@singletons/path'; | ||||
| import { CorePromisedValue } from '@classes/promised-value'; | ||||
| import { CorePlatform } from '@services/platform'; | ||||
| import { CoreCourse } from '@features/course/services/course'; | ||||
| import { CorePasswordModalResponse } from '@components/password-modal/password-modal'; | ||||
| import { CoreTime } from '@singletons/time'; | ||||
| import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; | ||||
| @ -316,32 +315,40 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { | ||||
|         const guestInstanceId = await this.guestInstanceId; | ||||
|         if (this.useGuestAccess && this.guestAccessPasswordRequired && guestInstanceId) { | ||||
|             // Check if the user has access to the course as guest with a previous sent password.
 | ||||
|             let validated = await CoreUtils.promiseWorks( | ||||
|                 CoreCourse.getSections(this.courseId, true, true, { getFromCache: false, emergencyCache: false }, undefined, false), | ||||
|             ); | ||||
|             let validated = await CoreCourseHelper.userHasAccessToCourse(this.courseId); | ||||
| 
 | ||||
|             if (!validated) { | ||||
|                 try { | ||||
|                     const validatePassword = async (password: string): Promise<CorePasswordModalResponse> => { | ||||
|                         const response = await CoreCourses.validateGuestAccessPassword(guestInstanceId, password); | ||||
|                     type ValidatorResponse = CorePasswordModalResponse & { cancel?: boolean }; | ||||
|                     const validatePassword = async (password: string): Promise<ValidatorResponse> => { | ||||
|                         try { | ||||
|                             const response = await CoreCourses.validateGuestAccessPassword(guestInstanceId, password); | ||||
| 
 | ||||
|                         validated = response.validated; | ||||
|                         let error = response.hint; | ||||
|                         if (!validated && !error) { | ||||
|                             error = 'core.course.guestaccess_passwordinvalid'; | ||||
|                             validated = response.validated; | ||||
|                             let error = response.hint; | ||||
|                             if (!validated && !error) { | ||||
|                                 error = 'core.course.guestaccess_passwordinvalid'; | ||||
|                             } | ||||
| 
 | ||||
|                             return { | ||||
|                                 password, validated, error, | ||||
|                             }; | ||||
|                         } catch { | ||||
|                             this.refreshData(); | ||||
| 
 | ||||
|                             return { | ||||
|                                 password, | ||||
|                                 cancel: true, | ||||
|                             }; | ||||
|                         } | ||||
| 
 | ||||
|                         return { | ||||
|                             password, validated, error, | ||||
|                         }; | ||||
|                     }; | ||||
| 
 | ||||
|                     const response = await CoreDomUtils.promptPassword({ | ||||
|                     const response = await CoreDomUtils.promptPassword<ValidatorResponse>({ | ||||
|                         title: 'core.course.guestaccess', | ||||
|                         validator: validatePassword, | ||||
|                     }); | ||||
| 
 | ||||
|                     if (!response.validated) { | ||||
|                     if (!response.validated || response.cancel) { | ||||
|                         return; | ||||
|                     } | ||||
|                 } catch { | ||||
|  | ||||
| @ -1940,6 +1940,24 @@ export class CoreCourseHelperProvider { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if user can access the course. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @returns Promise resolved with boolean: whether user can access the course. | ||||
|      */ | ||||
|     async userHasAccessToCourse(courseId: number): Promise<boolean> { | ||||
|         if (CoreNetwork.isOnline()) { | ||||
|             return CoreUtils.promiseWorks( | ||||
|                 CoreCourse.getSections(courseId, true, true, { getFromCache: false, emergencyCache: false }, undefined, false), | ||||
|             ); | ||||
|         } else { | ||||
|             return CoreUtils.promiseWorks( | ||||
|                 CoreCourse.getSections(courseId, true, true, { getCacheUsingCacheKey: true }, undefined, false), | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete course files. | ||||
|      * | ||||
|  | ||||
| @ -176,7 +176,7 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|      */ | ||||
|     openCourse(): void { | ||||
|         if (this.isEnrolled) { | ||||
|             CoreCourseHelper.openCourse(this.course); | ||||
|             CoreCourseHelper.openCourse(this.course, { params: { isGuest: false } }); | ||||
|         } else { | ||||
|             CoreNavigator.navigateToSitePath( | ||||
|                 `/course/${this.course.id}/summary`, | ||||
|  | ||||
| @ -18,15 +18,13 @@ import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler'; | ||||
| import { CoreCourse } from '@features/course/services/course'; | ||||
| import { CoreCourseHelper } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseAnyCourseData, CoreCourses, CoreCoursesProvider, CoreEnrolledCourseData } from '../courses'; | ||||
| import { CoreCourses } from '../courses'; | ||||
| import { CoreLogger } from '@singletons/logger'; | ||||
| import { makeSingleton, Translate } from '@singletons'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; | ||||
| import { Params } from '@angular/router'; | ||||
| import { CoreError } from '@classes/errors/error'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreIonLoadingElement } from '@classes/ion-loading'; | ||||
| import { CoreNavigator } from '@services/navigator'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to treat links to course view or enrol (except site home). | ||||
| @ -76,7 +74,7 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler | ||||
|         return [{ | ||||
|             action: (siteId): void => { | ||||
|                 siteId = siteId || CoreSites.getCurrentSiteId(); | ||||
|                 if (siteId == CoreSites.getCurrentSiteId()) { | ||||
|                 if (siteId === CoreSites.getCurrentSiteId()) { | ||||
|                     // Check if we already are in the course index page.
 | ||||
|                     if (CoreCourse.currentViewIsCourse(courseId)) { | ||||
|                         // Current view is this course, just select the contents tab.
 | ||||
| @ -119,209 +117,45 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler | ||||
|      * @returns Promise resolved when done. | ||||
|      */ | ||||
|     protected async actionOpen(courseId: number, url: string, pageParams: Params): Promise<void> { | ||||
|         const modal = await CoreDomUtils.showModalLoading(); | ||||
|         let course: CoreCourseAnyCourseData | { id: number } | undefined; | ||||
| 
 | ||||
|         // Check if user is enrolled in the course.
 | ||||
|         try { | ||||
|             course = await CoreCourses.getUserCourse(courseId); | ||||
|         } catch { | ||||
|             course = await this.checkSelfUserCanSelfEnrolOrAccess(courseId, url, modal); | ||||
|         } | ||||
| 
 | ||||
|         // Check if we need to retrieve the course.
 | ||||
|         if (!course) { | ||||
|             try { | ||||
|                 const data = await CoreCourseHelper.getCourse(courseId); | ||||
|                 course = data.course; | ||||
|             } catch { | ||||
|                 // Cannot get course, return a "fake".
 | ||||
|                 course = { id: courseId }; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         modal.dismiss(); | ||||
| 
 | ||||
|         // Now open the course.
 | ||||
|         CoreCourseHelper.openCourse(course, { params: pageParams }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the user can self enrol or access the course. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param url Treated URL. | ||||
|      * @param modal Modal, to dismiss when needed. | ||||
|      * @returns The course after self enrolling or undefined if the user has access but is not enrolled. | ||||
|      */ | ||||
|     protected async checkSelfUserCanSelfEnrolOrAccess( | ||||
|         courseId: number, | ||||
|         url: string, | ||||
|         modal: CoreIonLoadingElement, | ||||
|     ): Promise<CoreEnrolledCourseData | undefined> { | ||||
|         const isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/); | ||||
|         if (isEnrolUrl) { | ||||
|             this.navigateCourseSummary(courseId, pageParams); | ||||
| 
 | ||||
|         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; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // 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; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // 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')], | ||||
|             ); | ||||
| 
 | ||||
|             try { | ||||
|                 await CoreDomUtils.showConfirm(body); | ||||
| 
 | ||||
|                 CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(url, undefined, { showBrowserWarning: false }); | ||||
|             } catch { | ||||
|                 // User cancelled.
 | ||||
|             } | ||||
| 
 | ||||
|             throw new CoreError(notEnrolledMessage); | ||||
|         } | ||||
| 
 | ||||
|         // The user can self enrol. If it's not a enrolment URL we'll ask for confirmation.
 | ||||
|         modal.dismiss(); | ||||
| 
 | ||||
|         if (!isEnrolUrl) { | ||||
|             await CoreDomUtils.showConfirm(Translate.instant('core.courses.confirmselfenrol')); | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             return await this.selfEnrol(courseId); | ||||
|         } catch (error) { | ||||
|             if (error) { | ||||
|                 CoreDomUtils.showErrorModal(error); | ||||
|             } | ||||
| 
 | ||||
|             throw error; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if user can access the course. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @returns Promise resolved with boolean: whether user can access the course. | ||||
|      */ | ||||
|     protected canAccess(courseId: number): Promise<boolean> { | ||||
|         return CoreUtils.promiseWorks(CoreCourse.getSections(courseId, false, true)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if a user can be "automatically" self enrolled in a course. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @returns Promise resolved with boolean: whether the user can be enrolled in a course. | ||||
|      */ | ||||
|     protected async canSelfEnrol(courseId: number): Promise<boolean> { | ||||
|         try { | ||||
|             // Check that the course has self enrolment enabled.
 | ||||
|             const methods = await CoreCourses.getCourseEnrolmentMethods(courseId); | ||||
| 
 | ||||
|             let isSelfEnrolEnabled = false; | ||||
|             let instances = 0; | ||||
|             methods.forEach((method) => { | ||||
|                 if (method.type == 'self' && CoreUtils.isTrueOrOne(method.status)) { | ||||
|                     isSelfEnrolEnabled = true; | ||||
|                     instances++; | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             return isSelfEnrolEnabled && instances === 1; | ||||
|         } catch { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Try to self enrol a user in a course. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param password Password. | ||||
|      * @returns Promise resolved when the user is enrolled, rejected otherwise. | ||||
|      */ | ||||
|     protected async selfEnrol(courseId: number, password?: string): Promise<CoreEnrolledCourseData | undefined> { | ||||
|         const modal = await CoreDomUtils.showModalLoading(); | ||||
| 
 | ||||
|         try { | ||||
|             await CoreCourses.selfEnrol(courseId, password); | ||||
|         // Check if user is enrolled in the course.
 | ||||
|         const hasAccess = await CoreCourseHelper.userHasAccessToCourse(courseId); | ||||
| 
 | ||||
|             try { | ||||
|                 // Sometimes the list of enrolled courses takes a while to be updated. Wait for it.
 | ||||
|                 return await this.waitForEnrolled(courseId, true); | ||||
|             } finally { | ||||
|                 modal.dismiss(); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             modal.dismiss(); | ||||
|         const guestInfo = await CoreCourseHelper.courseUsesGuestAccessInfo(courseId); | ||||
|         pageParams.isGuest = guestInfo.guestAccess; | ||||
| 
 | ||||
|             if (error && error.errorcode === CoreCoursesProvider.ENROL_INVALID_KEY) { | ||||
|                 // Invalid password. Allow the user to input password.
 | ||||
|                 const title = Translate.instant('core.courses.selfenrolment'); | ||||
|                 let body = ' '; // Empty message.
 | ||||
|                 const placeholder = Translate.instant('core.courses.password'); | ||||
|         if (hasAccess && !guestInfo.guestAccess && !guestInfo.passwordRequired) { | ||||
|             // Direct access.
 | ||||
|             const course = await CoreUtils.ignoreErrors(CoreCourses.getUserCourse(courseId), { id: courseId }); | ||||
| 
 | ||||
|                 if (password !== undefined) { | ||||
|                     // The user attempted a password. Show an error message.
 | ||||
|                     body = CoreTextUtils.getErrorMessageFromError(error) || body; | ||||
|                 } | ||||
|             CoreCourseHelper.openCourse(course, pageParams); | ||||
|         } else { | ||||
|             this.navigateCourseSummary(courseId, pageParams); | ||||
| 
 | ||||
|                 password = await CoreDomUtils.showPrompt(body, title, placeholder); | ||||
| 
 | ||||
|                 await this.selfEnrol(courseId, password); | ||||
|             } else { | ||||
|                 throw error; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         modal.dismiss(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Wait for the user to be enrolled in a course. | ||||
|      * Navigate course summary. | ||||
|      * | ||||
|      * @param courseId The course ID. | ||||
|      * @param first If it's the first call (true) or it's a recursive call (false). | ||||
|      * @returns Promise resolved when enrolled or timeout. | ||||
|      * @param courseId Course ID. | ||||
|      * @param pageParams Params to send to the new page. | ||||
|      */ | ||||
|     protected async waitForEnrolled(courseId: number, first?: boolean): Promise<CoreEnrolledCourseData | undefined> { | ||||
|         if (first) { | ||||
|             this.waitStart = Date.now(); | ||||
|         } | ||||
| 
 | ||||
|         // Check if user is enrolled in the course.
 | ||||
|         await CoreUtils.ignoreErrors(CoreCourses.invalidateUserCourses()); | ||||
|         try { | ||||
|             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; | ||||
|             } | ||||
| 
 | ||||
|             await CoreUtils.wait(5000); | ||||
| 
 | ||||
|             return this.waitForEnrolled(courseId); | ||||
|         } | ||||
|     protected navigateCourseSummary(courseId: number, pageParams: Params): void { | ||||
|         CoreNavigator.navigateToSitePath( | ||||
|             `/course/${courseId}/summary`, | ||||
|             { params: pageParams }, | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1887,11 +1887,11 @@ export class CoreDomUtilsProvider { | ||||
|      * @param passwordParams Params to show the modal. | ||||
|      * @returns Entered password, error and validation. | ||||
|      */ | ||||
|     async promptPassword(passwordParams?: CorePasswordModalParams): Promise<CorePasswordModalResponse> { | ||||
|     async promptPassword<T extends CorePasswordModalResponse>(passwordParams?: CorePasswordModalParams): Promise<T> { | ||||
|         const { CorePasswordModalComponent } = | ||||
|             await import('@/core/components/password-modal/password-modal.module'); | ||||
| 
 | ||||
|         const modalData = await CoreDomUtils.openModal<CorePasswordModalResponse>( | ||||
|         const modalData = await CoreDomUtils.openModal<T>( | ||||
|             { | ||||
|                 cssClass: 'core-password-modal', | ||||
|                 showBackdrop: true, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user