Merge pull request #2953 from dpalou/MOBILE-3848
MOBILE-3848 dashboard: Support guest courses in recently accessed
This commit is contained in:
		
						commit
						24e4f5797d
					
				| @ -16,7 +16,7 @@ import { Component, OnInit, OnDestroy, Input, OnChanges, SimpleChange } from '@a | ||||
| import { CoreEventObserver, CoreEvents } from '@singletons/events'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData, CoreCourses } from '@features/courses/services/courses'; | ||||
| import { CoreCoursesHelper, CoreEnrolledCourseDataWithOptions } from '@features/courses/services/courses-helper'; | ||||
| import { CoreCourseSearchedDataWithExtraInfoAndOptions, CoreCoursesHelper } from '@features/courses/services/courses-helper'; | ||||
| import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate'; | ||||
| import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion'; | ||||
| @ -35,7 +35,7 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom | ||||
| 
 | ||||
|     @Input() downloadEnabled = false; | ||||
| 
 | ||||
|     courses: CoreEnrolledCourseDataWithOptions [] = []; | ||||
|     courses: CoreCourseSearchedDataWithExtraInfoAndOptions[] = []; | ||||
|     prefetchCoursesData: CorePrefetchStatusInfo = { | ||||
|         icon: '', | ||||
|         statusTranslatable: 'core.loading', | ||||
| @ -112,7 +112,7 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom | ||||
|     protected async invalidateContent(): Promise<void> { | ||||
|         const promises: Promise<void>[] = []; | ||||
| 
 | ||||
|         promises.push(CoreCourses.invalidateUserCourses().finally(() => | ||||
|         promises.push(CoreCourses.invalidateRecentCourses().finally(() => | ||||
|             // Invalidate course completion data.
 | ||||
|             CoreUtils.allPromises(this.courseIds.map((courseId) => | ||||
|                 AddonCourseCompletion.invalidateCourseCompletion(courseId))))); | ||||
| @ -136,7 +136,33 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom | ||||
|         const showCategories = this.block.configsRecord && this.block.configsRecord.displaycategories && | ||||
|             this.block.configsRecord.displaycategories.value == '1'; | ||||
| 
 | ||||
|         this.courses = await CoreCoursesHelper.getUserCoursesWithOptions('lastaccess', 10, undefined, showCategories); | ||||
|         const recentCourses = await CoreCourses.getRecentCourses(); | ||||
|         const courseIds = recentCourses.map((course) => course.id); | ||||
| 
 | ||||
|         // Get the courses using getCoursesByField to get more info about each course.
 | ||||
|         const courses: CoreCourseSearchedDataWithExtraInfoAndOptions[] = await CoreCourses.getCoursesByField( | ||||
|             'ids', | ||||
|             courseIds.join(','), | ||||
|         ); | ||||
| 
 | ||||
|         // Sort them in the original order.
 | ||||
|         courses.sort((courseA, courseB) => courseIds.indexOf(courseA.id) - courseIds.indexOf(courseB.id)); | ||||
| 
 | ||||
|         // Get course options and extra info.
 | ||||
|         const options = await CoreCourses.getCoursesAdminAndNavOptions(courseIds); | ||||
|         courses.forEach((course) => { | ||||
|             course.navOptions = options.navOptions[course.id]; | ||||
|             course.admOptions = options.admOptions[course.id]; | ||||
| 
 | ||||
|             if (!showCategories) { | ||||
|                 course.categoryname = ''; | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         await CoreCoursesHelper.loadCoursesColorAndImage(courses); | ||||
| 
 | ||||
|         this.courses = courses; | ||||
| 
 | ||||
|         this.initPrefetchCoursesIcons(); | ||||
|     } | ||||
| 
 | ||||
| @ -148,11 +174,7 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom | ||||
|     protected async refreshCourseList(): Promise<void> { | ||||
|         CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED); | ||||
| 
 | ||||
|         try { | ||||
|             await CoreCourses.invalidateUserCourses(); | ||||
|         } catch (error) { | ||||
|             // Ignore errors.
 | ||||
|         } | ||||
|         await CoreUtils.ignoreErrors(CoreCourses.invalidateRecentCourses()); | ||||
| 
 | ||||
|         await this.loadContent(true); | ||||
|     } | ||||
|  | ||||
| @ -39,7 +39,6 @@ import { | ||||
|     CoreCourseSearchedData, | ||||
|     CoreEnrolledCourseData, | ||||
| } from '@features/courses/services/courses'; | ||||
| import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '@features/courses/services/courses-helper'; | ||||
| import { CoreArray } from '@singletons/array'; | ||||
| import { CoreIonLoadingElement } from '@classes/ion-loading'; | ||||
| import { CoreCourseOffline } from './course-offline'; | ||||
| @ -424,7 +423,7 @@ export class CoreCourseHelperProvider { | ||||
|      * @return Resolved when downloaded, rejected if error or canceled. | ||||
|      */ | ||||
|     async confirmAndPrefetchCourses( | ||||
|         courses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], | ||||
|         courses: CoreCourseAnyCourseData[], | ||||
|         options: CoreCourseConfirmPrefetchCoursesOptions = {}, | ||||
|     ): Promise<void> { | ||||
|         const siteId = CoreSites.getCurrentSiteId(); | ||||
| @ -1302,7 +1301,7 @@ export class CoreCourseHelperProvider { | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async prefetchCourses( | ||||
|         courses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], | ||||
|         courses: CoreCourseAnyCourseData[], | ||||
|         prefetch: CorePrefetchStatusInfo, | ||||
|         options: CoreCoursePrefetchCoursesOptions = {}, | ||||
|     ): Promise<void> { | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|     </div> | ||||
|     <ion-item button lines="none" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" | ||||
|         class="core-course-header" [class.item-disabled]="course.visible == 0" | ||||
|         [class.core-course-only-title]="!showAll || course.progress! < 0 && course.completionusertracked === false" | ||||
|         [class.core-course-only-title]="!showAll || progress < 0 && completionUserTracked === false" | ||||
|         detail="false"> | ||||
|         <ion-label | ||||
|             class="ion-text-wrap core-course-title" | ||||
| @ -26,9 +26,9 @@ | ||||
|                 </span> | ||||
|             </p> | ||||
|             <p class="item-heading"> | ||||
|                 <ion-icon name="fas-star" *ngIf="course.isfavourite" [attr.aria-label]="'core.courses.favourite' | translate"> | ||||
|                 <ion-icon name="fas-star" *ngIf="isFavourite" [attr.aria-label]="'core.courses.favourite' | translate"> | ||||
|                 </ion-icon> | ||||
|                 <span class="sr-only" *ngIf="course.isfavourite">{{ 'core.courses.aria:favourite' | translate }}</span> | ||||
|                 <span class="sr-only" *ngIf="isFavourite">{{ 'core.courses.aria:favourite' | translate }}</span> | ||||
|                 <span class="sr-only">{{ 'core.courses.aria:coursename' | translate }}</span> | ||||
|                 <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"></core-format-text> | ||||
|             </p> | ||||
| @ -61,10 +61,10 @@ | ||||
|             </ion-button> | ||||
|         </div> | ||||
|     </ion-item> | ||||
|     <ion-item *ngIf="showAll && course.progress! >= 0 && course.completionusertracked !== false" lines="none" | ||||
|     <ion-item *ngIf="showAll && progress >= 0 && completionUserTracked !== false" lines="none" | ||||
|         class="core-course-progress"> | ||||
|         <ion-label> | ||||
|             <core-progress-bar [progress]="course.progress" a11yText="core.courses.aria:courseprogress"></core-progress-bar> | ||||
|             <core-progress-bar [progress]="progress" a11yText="core.courses.aria:courseprogress"></core-progress-bar> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ng-content></ng-content> | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnInit, OnDestroy } from '@angular/core'; | ||||
| import { Component, Input, OnInit, OnDestroy, OnChanges } from '@angular/core'; | ||||
| import { CoreEventCourseStatusChanged, CoreEventObserver, CoreEvents } from '@singletons/events'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| @ -21,7 +21,10 @@ import { CoreCourse, CoreCourseProvider } from '@features/course/services/course | ||||
| import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { CoreConstants } from '@/core/constants'; | ||||
| import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '../../services/courses-helper'; | ||||
| import { | ||||
|     CoreCourseAnyCourseDataWithExtraInfoAndOptions, | ||||
|     CoreEnrolledCourseDataWithExtraInfoAndOptions, | ||||
| } from '../../services/courses-helper'; | ||||
| import { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu'; | ||||
| import { CoreUser } from '@features/user/services/user'; | ||||
| 
 | ||||
| @ -38,9 +41,10 @@ import { CoreUser } from '@features/user/services/user'; | ||||
|     templateUrl: 'core-courses-course-progress.html', | ||||
|     styleUrls: ['course-progress.scss'], | ||||
| }) | ||||
| export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||
| export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy, OnChanges { | ||||
| 
 | ||||
|     @Input() course!: CoreEnrolledCourseDataWithExtraInfoAndOptions; // The course to render.
 | ||||
|     // The course to render.
 | ||||
|     @Input() course!: CoreCourseAnyCourseDataWithExtraInfoAndOptions; | ||||
|     @Input() showAll = false; // If true, will show all actions, options, star and progress.
 | ||||
|     @Input() showDownload = true; // If true, will show download button. Only works if the options menu is not shown.
 | ||||
| 
 | ||||
| @ -56,13 +60,16 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||
|     showSpinner = false; | ||||
|     downloadCourseEnabled = false; | ||||
|     courseOptionMenuEnabled = false; | ||||
|     isFavourite = false; | ||||
|     progress = -1; | ||||
|     completionUserTracked: boolean | undefined = false; | ||||
| 
 | ||||
|     protected isDestroyed = false; | ||||
|     protected courseStatusObserver?: CoreEventObserver; | ||||
|     protected siteUpdatedObserver?: CoreEventObserver; | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
| 
 | ||||
| @ -73,7 +80,8 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||
|         } | ||||
| 
 | ||||
|         // This field is only available from 3.6 onwards.
 | ||||
|         this.courseOptionMenuEnabled = this.showAll && typeof this.course.isfavourite != 'undefined'; | ||||
|         this.courseOptionMenuEnabled = this.showAll && 'isfavourite' in this.course && | ||||
|             typeof this.course.isfavourite != 'undefined'; | ||||
| 
 | ||||
|         // Refresh the enabled flag if site is updated.
 | ||||
|         this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => { | ||||
| @ -88,6 +96,15 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||
|         }, CoreSites.getCurrentSiteId()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnChanges(): void { | ||||
|         this.isFavourite = 'isfavourite' in this.course && !!this.course.isfavourite; | ||||
|         this.progress = 'progress' in this.course ? this.course.progress || -1 : -1; | ||||
|         this.completionUserTracked = 'completionusertracked' in this.course && this.course.completionusertracked; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize prefetch course. | ||||
|      */ | ||||
| @ -255,7 +272,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||
|                 hide ? '1' : undefined, | ||||
|             ); | ||||
| 
 | ||||
|             this.course.hidden = hide; | ||||
|             (<CoreEnrolledCourseDataWithExtraInfoAndOptions> this.course).hidden = hide; | ||||
|             CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, { | ||||
|                 courseId: this.course.id, | ||||
|                 course: this.course, | ||||
| @ -284,7 +301,8 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||
|         try { | ||||
|             await CoreCourses.setFavouriteCourse(this.course.id, favourite); | ||||
| 
 | ||||
|             this.course.isfavourite = favourite; | ||||
|             (<CoreEnrolledCourseDataWithExtraInfoAndOptions> this.course).isfavourite = favourite; | ||||
|             this.isFavourite = favourite; | ||||
|             CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, { | ||||
|                 courseId: this.course.id, | ||||
|                 course: this.course, | ||||
|  | ||||
| @ -15,7 +15,13 @@ | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreCourses, CoreCourseSearchedData, CoreCourseUserAdminOrNavOptionIndexed, CoreEnrolledCourseData } from './courses'; | ||||
| import { | ||||
|     CoreCourseAnyCourseDataWithOptions, | ||||
|     CoreCourses, | ||||
|     CoreCourseSearchedData, | ||||
|     CoreCourseUserAdminOrNavOptionIndexed, | ||||
|     CoreEnrolledCourseData, | ||||
| } from './courses'; | ||||
| import { makeSingleton, Translate } from '@singletons'; | ||||
| import { CoreWSExternalFile } from '@services/ws'; | ||||
| import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion'; | ||||
| @ -83,6 +89,31 @@ export class CoreCoursesHelperProvider { | ||||
|         this.loadCourseColorAndImage(course, colors); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Given a list of courses returned by core_enrol_get_users_courses, load some extra data using the WebService | ||||
|      * core_course_get_courses_by_field if available. | ||||
|      * | ||||
|      * @param courses List of courses. | ||||
|      * @param loadCategoryNames Whether load category names or not. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     /** | ||||
|      * Loads the color of courses or the thumb image. | ||||
|      * | ||||
|      * @param courses List of courses. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async loadCoursesColorAndImage(courses: CoreCourseSearchedData[]): Promise<void> { | ||||
|         if (!courses.length) { | ||||
|             return; | ||||
|         } | ||||
|         const colors = await this.loadCourseSiteColors(); | ||||
| 
 | ||||
|         courses.forEach((course) => { | ||||
|             this.loadCourseColorAndImage(course, colors); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Given a list of courses returned by core_enrol_get_users_courses, load some extra data using the WebService | ||||
|      * core_course_get_courses_by_field if available. | ||||
| @ -301,7 +332,27 @@ export type CoreEnrolledCourseDataWithOptions = CoreEnrolledCourseData & { | ||||
|     admOptions?: CoreCourseUserAdminOrNavOptionIndexed; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Course summary data with admin and navigation option availability. | ||||
|  */ | ||||
| export type CoreCourseSearchedDataWithOptions = CoreCourseSearchedData & { | ||||
|     navOptions?: CoreCourseUserAdminOrNavOptionIndexed; | ||||
|     admOptions?: CoreCourseUserAdminOrNavOptionIndexed; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Enrolled course data with admin and navigation option availability and extra rendering info. | ||||
|  */ | ||||
| export type CoreEnrolledCourseDataWithExtraInfoAndOptions = CoreEnrolledCourseDataWithExtraInfo & CoreEnrolledCourseDataWithOptions; | ||||
| 
 | ||||
| /** | ||||
|  * Searched course data with admin and navigation option availability and extra rendering info. | ||||
|  */ | ||||
| export type CoreCourseSearchedDataWithExtraInfoAndOptions = CoreCourseWithImageAndColor & CoreCourseSearchedDataWithOptions; | ||||
| 
 | ||||
| /** | ||||
|  * Any course data with admin and navigation option availability and extra rendering info. | ||||
|  */ | ||||
| export type CoreCourseAnyCourseDataWithExtraInfoAndOptions = CoreCourseWithImageAndColor & CoreCourseAnyCourseDataWithOptions & { | ||||
|     categoryname?: string; // Category name,
 | ||||
| }; | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreLogger } from '@singletons/logger'; | ||||
| import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; | ||||
| import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites'; | ||||
| import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreStatusWithWarningsWSResponse, CoreWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; | ||||
| @ -45,6 +45,7 @@ declare module '@singletons/events' { | ||||
| export class CoreCoursesProvider { | ||||
| 
 | ||||
|     static readonly SEARCH_PER_PAGE = 20; | ||||
|     static readonly RECENT_PER_PAGE = 10; | ||||
|     static readonly ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey'; | ||||
|     static readonly EVENT_MY_COURSES_CHANGED = 'courses_my_courses_changed'; // User course list changed while app is running.
 | ||||
|     // A course was hidden/favourite, or user enroled in a course.
 | ||||
| @ -566,7 +567,7 @@ export class CoreCoursesProvider { | ||||
|         customFieldName: string, | ||||
|         customFieldValue: string, | ||||
|         siteId?: string, | ||||
|     ): Promise<CoreCourseGetEnrolledCoursesByTimelineClassification[]> { | ||||
|     ): Promise<CoreCourseSummaryData[]> { | ||||
|         const site = await CoreSites.getSite(siteId); | ||||
|         const params: CoreCourseGetEnrolledCoursesByTimelineClassificationWSParams = { | ||||
|             classification: 'customfield', | ||||
| @ -648,6 +649,40 @@ export class CoreCoursesProvider { | ||||
|         return ({ navOptions: navOptions, admOptions: admOptions }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get cache key for get recent courses WS call. | ||||
|      * | ||||
|      * @param userId User ID. | ||||
|      * @return Cache key. | ||||
|      */ | ||||
|     protected getRecentCoursesCacheKey(userId: number): string { | ||||
|         return `${ROOT_CACHE_KEY}:recentcourses:${userId}`; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get recent courses. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @return Promise resolved with courses. | ||||
|      * @since 3.6 | ||||
|      */ | ||||
|     async getRecentCourses(options: CoreCourseGetRecentCoursesOptions = {}): Promise<CoreCourseSummaryData[]> { | ||||
|         const site = await CoreSites.getSite(options.siteId); | ||||
| 
 | ||||
|         const userId = options.userId || site.getUserId(); | ||||
|         const params: CoreCourseGetRecentCoursesWSParams = { | ||||
|             userid: userId, | ||||
|             offset: options.offset || 0, | ||||
|             limit: options.limit || CoreCoursesProvider.RECENT_PER_PAGE, | ||||
|             sort: options.sort, | ||||
|         }; | ||||
|         const preSets: CoreSiteWSPreSets = { | ||||
|             cacheKey: this.getRecentCoursesCacheKey(userId), | ||||
|         }; | ||||
| 
 | ||||
|         return await site.read<CoreCourseSummaryData[]>('core_course_get_recent_courses', params, preSets); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the common part of the cache keys for user administration options WS calls. | ||||
|      * | ||||
| @ -995,6 +1030,19 @@ export class CoreCoursesProvider { | ||||
|         return site.invalidateWsCacheForKey(this.getCoursesByFieldCacheKey(field, value)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates get recent courses WS call. | ||||
|      * | ||||
|      * @param userId User ID. If not defined, current user. | ||||
|      * @param siteId Site Id. If not defined, use current site. | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     async invalidateRecentCourses(userId?: number, siteId?: string): Promise<void> { | ||||
|         const site = await CoreSites.getSite(siteId); | ||||
| 
 | ||||
|         await site.invalidateWsCacheForKey(this.getRecentCoursesCacheKey(userId || site.getUserId())); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates all user administration options. | ||||
|      * | ||||
| @ -1428,13 +1476,15 @@ type CoreCourseGetCoursesWSParams = { | ||||
| export type CoreCourseGetCoursesWSResponse = CoreCourseGetCoursesData[]; | ||||
| 
 | ||||
| /** | ||||
|  * Course type exported in CoreCourseGetEnrolledCoursesByTimelineClassificationWSResponse; | ||||
|  * Course data exported by course_summary_exporter; | ||||
|  */ | ||||
| export type CoreCourseGetEnrolledCoursesByTimelineClassification = CoreCourseBasicData & { // Course.
 | ||||
| export type CoreCourseSummaryData = CoreCourseBasicData & { // Course.
 | ||||
|     idnumber: string; // Idnumber.
 | ||||
|     startdate: number; // Startdate.
 | ||||
|     enddate: number; // Enddate.
 | ||||
|     visible: boolean; // Visible.
 | ||||
|     showactivitydates: boolean; // Showactivitydates.
 | ||||
|     showcompletionconditions: boolean; // Showcompletionconditions.
 | ||||
|     fullnamedisplay: string; // Fullnamedisplay.
 | ||||
|     viewurl: string; // Viewurl.
 | ||||
|     courseimage: string; // Courseimage.
 | ||||
| @ -1463,7 +1513,7 @@ type CoreCourseGetEnrolledCoursesByTimelineClassificationWSParams = { | ||||
|  * Data returned by core_course_get_enrolled_courses_by_timeline_classification WS. | ||||
|  */ | ||||
| export type CoreCourseGetEnrolledCoursesByTimelineClassificationWSResponse = { | ||||
|     courses: CoreCourseGetEnrolledCoursesByTimelineClassification[]; | ||||
|     courses: CoreCourseSummaryData[]; | ||||
|     nextoffset: number; // Offset for the next request.
 | ||||
| }; | ||||
| 
 | ||||
| @ -1588,6 +1638,26 @@ export type EnrolGuestGetInstanceInfoWSResponse = { | ||||
|     warnings?: CoreWSExternalWarning[]; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Params of core_course_get_recent_courses WS. | ||||
|  */ | ||||
| export type CoreCourseGetRecentCoursesWSParams = { | ||||
|     userid?: number; // Id of the user, default to current user.
 | ||||
|     limit?: number; // Result set limit.
 | ||||
|     offset?: number; // Result set offset.
 | ||||
|     sort?: string; // Sort string.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Options for getRecentCourses. | ||||
|  */ | ||||
| export type CoreCourseGetRecentCoursesOptions = CoreSitesCommonWSOptions & { | ||||
|     userId?: number; // Id of the user, default to current user.
 | ||||
|     limit?: number; // Result set limit.
 | ||||
|     offset?: number; // Result set offset.
 | ||||
|     sort?: string; // Sort string.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Course guest enrolment method. | ||||
|  */ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user