Merge pull request #2953 from dpalou/MOBILE-3848

MOBILE-3848 dashboard: Support guest courses in recently accessed
main
Noel De Martin 2021-09-23 13:27:51 +02:00 committed by GitHub
commit 24e4f5797d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 191 additions and 31 deletions

View File

@ -16,7 +16,7 @@ import { Component, OnInit, OnDestroy, Input, OnChanges, SimpleChange } from '@a
import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData, CoreCourses } from '@features/courses/services/courses'; 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 { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper';
import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate'; import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate';
import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion'; import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion';
@ -35,7 +35,7 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
@Input() downloadEnabled = false; @Input() downloadEnabled = false;
courses: CoreEnrolledCourseDataWithOptions [] = []; courses: CoreCourseSearchedDataWithExtraInfoAndOptions[] = [];
prefetchCoursesData: CorePrefetchStatusInfo = { prefetchCoursesData: CorePrefetchStatusInfo = {
icon: '', icon: '',
statusTranslatable: 'core.loading', statusTranslatable: 'core.loading',
@ -112,7 +112,7 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
protected async invalidateContent(): Promise<void> { protected async invalidateContent(): Promise<void> {
const promises: Promise<void>[] = []; const promises: Promise<void>[] = [];
promises.push(CoreCourses.invalidateUserCourses().finally(() => promises.push(CoreCourses.invalidateRecentCourses().finally(() =>
// Invalidate course completion data. // Invalidate course completion data.
CoreUtils.allPromises(this.courseIds.map((courseId) => CoreUtils.allPromises(this.courseIds.map((courseId) =>
AddonCourseCompletion.invalidateCourseCompletion(courseId))))); AddonCourseCompletion.invalidateCourseCompletion(courseId)))));
@ -136,7 +136,33 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
const showCategories = this.block.configsRecord && this.block.configsRecord.displaycategories && const showCategories = this.block.configsRecord && this.block.configsRecord.displaycategories &&
this.block.configsRecord.displaycategories.value == '1'; 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(); this.initPrefetchCoursesIcons();
} }
@ -148,11 +174,7 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
protected async refreshCourseList(): Promise<void> { protected async refreshCourseList(): Promise<void> {
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED); CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED);
try { await CoreUtils.ignoreErrors(CoreCourses.invalidateRecentCourses());
await CoreCourses.invalidateUserCourses();
} catch (error) {
// Ignore errors.
}
await this.loadContent(true); await this.loadContent(true);
} }

View File

@ -39,7 +39,6 @@ import {
CoreCourseSearchedData, CoreCourseSearchedData,
CoreEnrolledCourseData, CoreEnrolledCourseData,
} from '@features/courses/services/courses'; } from '@features/courses/services/courses';
import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '@features/courses/services/courses-helper';
import { CoreArray } from '@singletons/array'; import { CoreArray } from '@singletons/array';
import { CoreIonLoadingElement } from '@classes/ion-loading'; import { CoreIonLoadingElement } from '@classes/ion-loading';
import { CoreCourseOffline } from './course-offline'; import { CoreCourseOffline } from './course-offline';
@ -424,7 +423,7 @@ export class CoreCourseHelperProvider {
* @return Resolved when downloaded, rejected if error or canceled. * @return Resolved when downloaded, rejected if error or canceled.
*/ */
async confirmAndPrefetchCourses( async confirmAndPrefetchCourses(
courses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], courses: CoreCourseAnyCourseData[],
options: CoreCourseConfirmPrefetchCoursesOptions = {}, options: CoreCourseConfirmPrefetchCoursesOptions = {},
): Promise<void> { ): Promise<void> {
const siteId = CoreSites.getCurrentSiteId(); const siteId = CoreSites.getCurrentSiteId();
@ -1302,7 +1301,7 @@ export class CoreCourseHelperProvider {
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
async prefetchCourses( async prefetchCourses(
courses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], courses: CoreCourseAnyCourseData[],
prefetch: CorePrefetchStatusInfo, prefetch: CorePrefetchStatusInfo,
options: CoreCoursePrefetchCoursesOptions = {}, options: CoreCoursePrefetchCoursesOptions = {},
): Promise<void> { ): Promise<void> {

View File

@ -5,7 +5,7 @@
</div> </div>
<ion-item button lines="none" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" <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-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"> detail="false">
<ion-label <ion-label
class="ion-text-wrap core-course-title" class="ion-text-wrap core-course-title"
@ -26,9 +26,9 @@
</span> </span>
</p> </p>
<p class="item-heading"> <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> </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> <span class="sr-only">{{ 'core.courses.aria:coursename' | translate }}</span>
<core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"></core-format-text> <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"></core-format-text>
</p> </p>
@ -61,10 +61,10 @@
</ion-button> </ion-button>
</div> </div>
</ion-item> </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"> class="core-course-progress">
<ion-label> <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-label>
</ion-item> </ion-item>
<ng-content></ng-content> <ng-content></ng-content>

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // 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 { CoreEventCourseStatusChanged, CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; 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 { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper';
import { Translate } from '@singletons'; import { Translate } from '@singletons';
import { CoreConstants } from '@/core/constants'; 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 { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu';
import { CoreUser } from '@features/user/services/user'; import { CoreUser } from '@features/user/services/user';
@ -38,9 +41,10 @@ import { CoreUser } from '@features/user/services/user';
templateUrl: 'core-courses-course-progress.html', templateUrl: 'core-courses-course-progress.html',
styleUrls: ['course-progress.scss'], 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() 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. @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; showSpinner = false;
downloadCourseEnabled = false; downloadCourseEnabled = false;
courseOptionMenuEnabled = false; courseOptionMenuEnabled = false;
isFavourite = false;
progress = -1;
completionUserTracked: boolean | undefined = false;
protected isDestroyed = false; protected isDestroyed = false;
protected courseStatusObserver?: CoreEventObserver; protected courseStatusObserver?: CoreEventObserver;
protected siteUpdatedObserver?: CoreEventObserver; protected siteUpdatedObserver?: CoreEventObserver;
/** /**
* Component being initialized. * @inheritdoc
*/ */
ngOnInit(): void { ngOnInit(): void {
@ -73,7 +80,8 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
} }
// This field is only available from 3.6 onwards. // 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. // Refresh the enabled flag if site is updated.
this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => { this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
@ -88,6 +96,15 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
}, CoreSites.getCurrentSiteId()); }, 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. * Initialize prefetch course.
*/ */
@ -255,7 +272,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
hide ? '1' : undefined, hide ? '1' : undefined,
); );
this.course.hidden = hide; (<CoreEnrolledCourseDataWithExtraInfoAndOptions> this.course).hidden = hide;
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, { CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
courseId: this.course.id, courseId: this.course.id,
course: this.course, course: this.course,
@ -284,7 +301,8 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
try { try {
await CoreCourses.setFavouriteCourse(this.course.id, favourite); 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, { CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
courseId: this.course.id, courseId: this.course.id,
course: this.course, course: this.course,

View File

@ -15,7 +15,13 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreSites } from '@services/sites'; 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 { makeSingleton, Translate } from '@singletons';
import { CoreWSExternalFile } from '@services/ws'; import { CoreWSExternalFile } from '@services/ws';
import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion'; import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion';
@ -83,6 +89,31 @@ export class CoreCoursesHelperProvider {
this.loadCourseColorAndImage(course, colors); 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 * 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. * core_course_get_courses_by_field if available.
@ -301,7 +332,27 @@ export type CoreEnrolledCourseDataWithOptions = CoreEnrolledCourseData & {
admOptions?: CoreCourseUserAdminOrNavOptionIndexed; 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. * Enrolled course data with admin and navigation option availability and extra rendering info.
*/ */
export type CoreEnrolledCourseDataWithExtraInfoAndOptions = CoreEnrolledCourseDataWithExtraInfo & CoreEnrolledCourseDataWithOptions; 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,
};

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLogger } from '@singletons/logger'; 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 { CoreSite, CoreSiteWSPreSets } from '@classes/site';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { CoreStatusWithWarningsWSResponse, CoreWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; import { CoreStatusWithWarningsWSResponse, CoreWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
@ -45,6 +45,7 @@ declare module '@singletons/events' {
export class CoreCoursesProvider { export class CoreCoursesProvider {
static readonly SEARCH_PER_PAGE = 20; static readonly SEARCH_PER_PAGE = 20;
static readonly RECENT_PER_PAGE = 10;
static readonly ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey'; static readonly ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
static readonly EVENT_MY_COURSES_CHANGED = 'courses_my_courses_changed'; // User course list changed while app is running. 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. // A course was hidden/favourite, or user enroled in a course.
@ -566,7 +567,7 @@ export class CoreCoursesProvider {
customFieldName: string, customFieldName: string,
customFieldValue: string, customFieldValue: string,
siteId?: string, siteId?: string,
): Promise<CoreCourseGetEnrolledCoursesByTimelineClassification[]> { ): Promise<CoreCourseSummaryData[]> {
const site = await CoreSites.getSite(siteId); const site = await CoreSites.getSite(siteId);
const params: CoreCourseGetEnrolledCoursesByTimelineClassificationWSParams = { const params: CoreCourseGetEnrolledCoursesByTimelineClassificationWSParams = {
classification: 'customfield', classification: 'customfield',
@ -648,6 +649,40 @@ export class CoreCoursesProvider {
return ({ navOptions: navOptions, admOptions: admOptions }); 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. * 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)); 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. * Invalidates all user administration options.
* *
@ -1428,13 +1476,15 @@ type CoreCourseGetCoursesWSParams = {
export type CoreCourseGetCoursesWSResponse = CoreCourseGetCoursesData[]; 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. idnumber: string; // Idnumber.
startdate: number; // Startdate. startdate: number; // Startdate.
enddate: number; // Enddate. enddate: number; // Enddate.
visible: boolean; // Visible. visible: boolean; // Visible.
showactivitydates: boolean; // Showactivitydates.
showcompletionconditions: boolean; // Showcompletionconditions.
fullnamedisplay: string; // Fullnamedisplay. fullnamedisplay: string; // Fullnamedisplay.
viewurl: string; // Viewurl. viewurl: string; // Viewurl.
courseimage: string; // Courseimage. courseimage: string; // Courseimage.
@ -1463,7 +1513,7 @@ type CoreCourseGetEnrolledCoursesByTimelineClassificationWSParams = {
* Data returned by core_course_get_enrolled_courses_by_timeline_classification WS. * Data returned by core_course_get_enrolled_courses_by_timeline_classification WS.
*/ */
export type CoreCourseGetEnrolledCoursesByTimelineClassificationWSResponse = { export type CoreCourseGetEnrolledCoursesByTimelineClassificationWSResponse = {
courses: CoreCourseGetEnrolledCoursesByTimelineClassification[]; courses: CoreCourseSummaryData[];
nextoffset: number; // Offset for the next request. nextoffset: number; // Offset for the next request.
}; };
@ -1588,6 +1638,26 @@ export type EnrolGuestGetInstanceInfoWSResponse = {
warnings?: CoreWSExternalWarning[]; 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. * Course guest enrolment method.
*/ */