MOBILE-3651 core: Specify some nulls in WS responses

main
Dani Palou 2021-02-18 15:17:36 +01:00
parent 1c443b183b
commit 05f5967ffc
12 changed files with 33 additions and 38 deletions

View File

@ -897,10 +897,7 @@ export class AddonMessagesProvider {
): Promise<{members: AddonMessagesConversationMember[]; canLoadMore: boolean}> { ): Promise<{members: AddonMessagesConversationMember[]; canLoadMore: boolean}> {
const site = await CoreSites.instance.getSite(siteId); const site = await CoreSites.instance.getSite(siteId);
userId = userId || site.getUserId(); userId = userId || site.getUserId();
limitTo = limitTo ?? AddonMessagesProvider.LIMIT_MESSAGES;
if (typeof limitTo == 'undefined' || limitTo === null) {
limitTo = AddonMessagesProvider.LIMIT_MESSAGES;
}
const preSets: CoreSiteWSPreSets = { const preSets: CoreSiteWSPreSets = {
cacheKey: this.getCacheKeyForConversationMembers(userId, conversationId), cacheKey: this.getCacheKeyForConversationMembers(userId, conversationId),
@ -948,11 +945,9 @@ export class AddonMessagesProvider {
options.userId = options.userId || site.getUserId(); options.userId = options.userId || site.getUserId();
options.limitFrom = options.limitFrom || 0; options.limitFrom = options.limitFrom || 0;
options.limitTo = options.limitTo === undefined || options.limitTo === null options.limitTo = options.limitTo ?? AddonMessagesProvider.LIMIT_MESSAGES;
? AddonMessagesProvider.LIMIT_MESSAGES
: options.limitTo;
options.timeFrom = options.timeFrom || 0; options.timeFrom = options.timeFrom || 0;
options.newestFirst = options.newestFirst === undefined || options.newestFirst === null ? true : options.newestFirst; options.newestFirst = options.newestFirst ?? true;
const preSets: CoreSiteWSPreSets = { const preSets: CoreSiteWSPreSets = {
cacheKey: this.getCacheKeyForConversationMessages(options.userId, conversationId), cacheKey: this.getCacheKeyForConversationMessages(options.userId, conversationId),

View File

@ -531,7 +531,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
} }
if (formattedData.lessonscored) { if (formattedData.lessonscored) {
if (formattedData.numofattempts) { if (formattedData.numofattempts && formattedData.avescore != null) {
formattedData.avescore = CoreTextUtils.instance.roundToDecimals(formattedData.avescore, 2); formattedData.avescore = CoreTextUtils.instance.roundToDecimals(formattedData.avescore, 2);
} }
if (formattedData.highscore != null) { if (formattedData.highscore != null) {

View File

@ -2231,14 +2231,14 @@ export class AddonModLessonProvider {
* @param data Data containing the user answer. * @param data Data containing the user answer.
* @return User response. * @return User response.
*/ */
protected getUserResponseMultichoice(data: Record<string, unknown>): number[] | null { protected getUserResponseMultichoice(data: Record<string, unknown>): number[] | undefined {
if (data.answer) { if (data.answer) {
// The data is already stored as expected. If it's valid, parse the values to int. // The data is already stored as expected. If it's valid, parse the values to int.
if (Array.isArray(data.answer)) { if (Array.isArray(data.answer)) {
return data.answer.map((value) => parseInt(value, 10)); return data.answer.map((value) => parseInt(value, 10));
} }
return null; return undefined;
} }
// Data is stored in properties like 'answer[379]'. Recreate the answer array. // Data is stored in properties like 'answer[379]'. Recreate the answer array.
@ -3979,12 +3979,12 @@ export type AddonModLessonGetAttemptsOverviewWSResponse = {
export type AddonModLessonAttemptsOverviewWSData = { export type AddonModLessonAttemptsOverviewWSData = {
lessonscored: boolean; // True if the lesson was scored. lessonscored: boolean; // True if the lesson was scored.
numofattempts: number; // Number of attempts. numofattempts: number; // Number of attempts.
avescore: number; // Average score. avescore: number | null; // Average score.
highscore: number; // High score. highscore: number | null; // High score.
lowscore: number; // Low score. lowscore: number | null; // Low score.
avetime: number; // Average time (spent in taking the lesson). avetime: number | null; // Average time (spent in taking the lesson).
hightime: number; // High time. hightime: number | null; // High time.
lowtime: number; // Low time. lowtime: number | null; // Low time.
students?: AddonModLessonAttemptsOverviewsStudentWSData[]; // Students data, including attempts. students?: AddonModLessonAttemptsOverviewsStudentWSData[]; // Students data, including attempts.
}; };
@ -4003,7 +4003,7 @@ export type AddonModLessonAttemptsOverviewsStudentWSData = {
*/ */
export type AddonModLessonAttemptsOverviewsAttemptWSData = { export type AddonModLessonAttemptsOverviewsAttemptWSData = {
try: number; // Attempt number. try: number; // Attempt number.
grade: number; // Attempt grade. grade: number | null; // Attempt grade.
timestart: number; // Attempt time started. timestart: number; // Attempt time started.
timeend: number; // Attempt last time continued. timeend: number; // Attempt last time continued.
end: number; // Attempt time ended. end: number; // Attempt time ended.

View File

@ -85,8 +85,8 @@ export class AddonModQuizProvider {
* @param decimals Decimals to use. * @param decimals Decimals to use.
* @return Grade to display. * @return Grade to display.
*/ */
formatGrade(grade?: number, decimals?: number): string { formatGrade(grade?: number | null, decimals?: number): string {
if (typeof grade == 'undefined' || grade == -1 || grade === null || isNaN(grade)) { if (grade === undefined || grade == -1 || grade === null || isNaN(grade)) {
return Translate.instance.instant('addon.mod_quiz.notyetgraded'); return Translate.instance.instant('addon.mod_quiz.notyetgraded');
} }
@ -1796,14 +1796,14 @@ export class AddonModQuizProvider {
* @return Grade to display. * @return Grade to display.
*/ */
rescaleGrade( rescaleGrade(
rawGrade: string | number | undefined, rawGrade: string | number | undefined | null,
quiz: AddonModQuizQuizWSData, quiz: AddonModQuizQuizWSData,
format: boolean | string = true, format: boolean | string = true,
): string | undefined { ): string | undefined {
let grade: number | undefined; let grade: number | undefined;
const rawGradeNum = typeof rawGrade == 'string' ? parseFloat(rawGrade) : rawGrade; const rawGradeNum = typeof rawGrade == 'string' ? parseFloat(rawGrade) : rawGrade;
if (rawGradeNum !== undefined && !isNaN(rawGradeNum)) { if (rawGradeNum !== undefined && rawGradeNum !== null && !isNaN(rawGradeNum)) {
if (quiz.sumgrades! >= 0.000005) { if (quiz.sumgrades! >= 0.000005) {
grade = rawGradeNum * quiz.grade! / quiz.sumgrades!; grade = rawGradeNum * quiz.grade! / quiz.sumgrades!;
} else { } else {
@ -2055,7 +2055,7 @@ export type AddonModQuizAttemptWSData = {
timemodified?: number; // Last modified time. timemodified?: number; // Last modified time.
timemodifiedoffline?: number; // Last modified time via webservices. timemodifiedoffline?: number; // Last modified time via webservices.
timecheckstate?: number; // Next time quiz cron should check attempt for state changes. NULL means never check. timecheckstate?: number; // Next time quiz cron should check attempt for state changes. NULL means never check.
sumgrades?: number; // Total marks for this attempt. sumgrades?: number | null; // Total marks for this attempt.
}; };
/** /**
@ -2215,7 +2215,7 @@ export type AddonModQuizQuizWSData = {
questionsperpage?: number; // How often to insert a page break when editing the quiz, or when shuffling the question order. questionsperpage?: number; // How often to insert a page break when editing the quiz, or when shuffling the question order.
navmethod?: string; // Any constraints on how the user is allowed to navigate around the quiz. navmethod?: string; // Any constraints on how the user is allowed to navigate around the quiz.
shuffleanswers?: number; // Whether the parts of the question should be shuffled, in those question types that support it. shuffleanswers?: number; // Whether the parts of the question should be shuffled, in those question types that support it.
sumgrades?: number; // The total of all the question instance maxmarks. sumgrades?: number | null; // The total of all the question instance maxmarks.
grade?: number; // The total that the quiz overall grade is scaled to be out of. grade?: number; // The total that the quiz overall grade is scaled to be out of.
timecreated?: number; // The time when the quiz was added to the course. timecreated?: number; // The time when the quiz was added to the course.
timemodified?: number; // Last modified time. timemodified?: number; // Last modified time.

View File

@ -160,9 +160,9 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
let section: CoreCourseSection | undefined; let section: CoreCourseSection | undefined;
if (typeof data.sectionId != 'undefined' && data.sectionId != null && this.sections) { if (typeof data.sectionId != 'undefined' && this.sections) {
section = this.sections.find((section) => section.id == data.sectionId); section = this.sections.find((section) => section.id == data.sectionId);
} else if (typeof data.sectionNumber != 'undefined' && data.sectionNumber != null && this.sections) { } else if (typeof data.sectionNumber != 'undefined' && this.sections) {
section = this.sections.find((section) => section.section == data.sectionNumber); section = this.sections.find((section) => section.section == data.sectionNumber);
} }
@ -184,8 +184,8 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
this.displaySectionSelector = CoreCourseFormatDelegate.instance.displaySectionSelector(this.course); this.displaySectionSelector = CoreCourseFormatDelegate.instance.displaySectionSelector(this.course);
this.displayBlocks = CoreCourseFormatDelegate.instance.displayBlocks(this.course); this.displayBlocks = CoreCourseFormatDelegate.instance.displayBlocks(this.course);
this.progress = 'progress' in this.course && this.course.progress !== undefined && this.course.progress >= 0 && this.progress = 'progress' in this.course && typeof this.course.progress == 'number' &&
this.course.completionusertracked !== false ? this.course.progress : undefined; this.course.progress >= 0 && this.course.completionusertracked !== false ? this.course.progress : undefined;
if ('overviewfiles' in this.course) { if ('overviewfiles' in this.course) {
this.imageThumb = this.course.overviewfiles?.[0]?.fileurl; this.imageThumb = this.course.overviewfiles?.[0]?.fileurl;
} }
@ -600,7 +600,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
this.completionChanged.emit(completionData); this.completionChanged.emit(completionData);
if (completionData.valueused !== false || !this.course || !('progress' in this.course) || if (completionData.valueused !== false || !this.course || !('progress' in this.course) ||
typeof this.course.progress == 'undefined') { typeof this.course.progress != 'number') {
return; return;
} }

View File

@ -23,7 +23,7 @@
<core-format-text [text]="course.displayname || course.fullname" contextLevel="course" [contextInstanceId]="course.id"> <core-format-text [text]="course.displayname || course.fullname" contextLevel="course" [contextInstanceId]="course.id">
</core-format-text> </core-format-text>
</h2> </h2>
<p *ngIf="isEnrolled && course.progress != null && course.progress! >= 0 && course.completionusertracked !== false"> <p *ngIf="isEnrolled && course.progress! >= 0 && course.completionusertracked !== false">
<core-progress-bar [progress]="course.progress"></core-progress-bar> <core-progress-bar [progress]="course.progress"></core-progress-bar>
</p> </p>
</ion-label> </ion-label>

View File

@ -34,7 +34,7 @@ export class CoreCoursesCourseListItemComponent implements OnInit {
@Input() course!: CoreCourseSearchedData & CoreCourseWithImageAndColor & { @Input() course!: CoreCourseSearchedData & CoreCourseWithImageAndColor & {
completionusertracked?: boolean; // If the user is completion tracked. completionusertracked?: boolean; // If the user is completion tracked.
progress?: number; // Progress percentage. progress?: number | null; // Progress percentage.
}; // The course to render. }; // The course to render.
icons: CoreCoursesEnrolmentIcons[] = []; icons: CoreCoursesEnrolmentIcons[] = [];

View File

@ -5,7 +5,7 @@
</div> </div>
<ion-item button lines="none" (click)="openCourse()" [title]="course.displayname || course.fullname" <ion-item button lines="none" (click)="openCourse()" [title]="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-more-than-title]="(course.progress != null && course.progress! >= 0)"> [class.core-course-more-than-title]="course.progress! >= 0">
<ion-label <ion-label
class="ion-text-wrap core-course-title" class="ion-text-wrap core-course-title"
[class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)" [class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)"
@ -50,7 +50,8 @@
</ion-button> </ion-button>
</div> </div>
</ion-item> </ion-item>
<ion-item *ngIf="showAll && course.progress != null && course.progress! >= 0 && course.completionusertracked !== false" lines="none"> <ion-item *ngIf="showAll && course.progress! >= 0 && course.completionusertracked !== false"
lines="none">
<ion-label><core-progress-bar [progress]="course.progress"></core-progress-bar></ion-label> <ion-label><core-progress-bar [progress]="course.progress"></core-progress-bar></ion-label>
</ion-item> </ion-item>
<ng-content></ng-content> <ng-content></ng-content>

View File

@ -1227,7 +1227,7 @@ export type CoreEnrolledCourseData = CoreEnrolledCourseBasicData & {
enrolledusercount?: number; // Number of enrolled users in this course. enrolledusercount?: number; // Number of enrolled users in this course.
completionhascriteria?: boolean; // If completion criteria is set. completionhascriteria?: boolean; // If completion criteria is set.
completionusertracked?: boolean; // If the user is completion tracked. completionusertracked?: boolean; // If the user is completion tracked.
progress?: number; // Progress percentage. progress?: number | null; // Progress percentage.
completed?: boolean; // Whether the course is completed. completed?: boolean; // Whether the course is completed.
marker?: number; // Course section marker. marker?: number; // Course section marker.
lastaccess?: number; // Last access to the course (timestamp). lastaccess?: number; // Last access to the course (timestamp).

View File

@ -26,7 +26,7 @@
<p class="ion-text-wrap">{{ site.fullName }}</p> <p class="ion-text-wrap">{{ site.fullName }}</p>
<p>{{ site.siteUrl }}</p> <p>{{ site.siteUrl }}</p>
</ion-label> </ion-label>
<p *ngIf="site.spaceUsage != null" slot="end"> <p *ngIf="site.spaceUsage !== undefined" slot="end">
{{ site.spaceUsage | coreBytesToSize }} {{ site.spaceUsage | coreBytesToSize }}
</p> </p>
<ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage(site)" <ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage(site)"

View File

@ -35,7 +35,7 @@
<ng-container *ngIf="!searchQuery"> <ng-container *ngIf="!searchQuery">
<h2>{{ participant.fullname }}</h2> <h2>{{ participant.fullname }}</h2>
<p *ngIf="participant.lastcourseaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastcourseaccess | coreTimeAgo }}</p> <p *ngIf="participant.lastcourseaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastcourseaccess | coreTimeAgo }}</p>
<p *ngIf="participant.lastcourseaccess == null && participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess | coreTimeAgo }}</p> <p *ngIf="!participant.lastcourseaccess && participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess | coreTimeAgo }}</p>
</ng-container> </ng-container>
<ng-container *ngIf="searchQuery"> <ng-container *ngIf="searchQuery">

View File

@ -964,7 +964,7 @@ export type CoreUserParticipant = CoreUserBasicData & {
interests?: string; // User interests (separated by commas). interests?: string; // User interests (separated by commas).
firstaccess?: number; // First access to the site (0 if never). firstaccess?: number; // First access to the site (0 if never).
lastaccess?: number; // Last access to the site (0 if never). lastaccess?: number; // Last access to the site (0 if never).
lastcourseaccess?: number; // Last access to the course (0 if never). lastcourseaccess?: number | null; // Last access to the course (0 if never).
description?: string; // User profile description. description?: string; // User profile description.
descriptionformat?: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN). descriptionformat?: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
city?: string; // Home city of the user. city?: string; // Home city of the user.
@ -1114,4 +1114,3 @@ type CoreEnrolSearchUsersWSParams = {
* Data returned by core_enrol_search_users WS. * Data returned by core_enrol_search_users WS.
*/ */
type CoreEnrolSearchUsersWSResponse = CoreUserData[]; type CoreEnrolSearchUsersWSResponse = CoreUserData[];