From 7fc1c96b0345f62eda6ef567ef80cd27776526ec Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Fri, 6 Sep 2019 09:25:30 +0200 Subject: [PATCH] MOBILE-3109 assign: Add return types to assign --- .../assign/classes/base-feedback-handler.ts | 20 +- .../assign/classes/base-submission-handler.ts | 39 +- .../classes/feedback-plugin-component.ts | 7 +- .../classes/submission-plugin-component.ts | 9 +- .../feedback-plugin/feedback-plugin.ts | 10 +- .../mod/assign/components/index/index.ts | 8 +- .../submission-plugin/submission-plugin.ts | 10 +- .../components/submission/submission.ts | 44 ++- .../feedback/comments/providers/handler.ts | 23 +- .../feedback/editpdf/providers/handler.ts | 11 +- .../assign/feedback/file/providers/handler.ts | 11 +- .../edit-feedback-modal.ts | 13 +- src/addon/mod/assign/pages/edit/edit.ts | 10 +- .../pages/submission-list/submission-list.ts | 28 +- .../submission-review/submission-review.ts | 4 +- src/addon/mod/assign/providers/assign-sync.ts | 16 +- src/addon/mod/assign/providers/assign.ts | 338 ++++++++++++++++-- .../mod/assign/providers/feedback-delegate.ts | 48 ++- src/addon/mod/assign/providers/helper.ts | 116 ++++-- .../mod/assign/providers/prefetch-handler.ts | 29 +- .../assign/providers/submission-delegate.ts | 79 ++-- .../submission/comments/providers/handler.ts | 12 +- .../submission/file/providers/handler.ts | 39 +- ...ddon-mod-assign-submission-onlinetext.html | 2 +- .../onlinetext/component/onlinetext.ts | 9 +- .../onlinetext/providers/handler.ts | 32 +- 26 files changed, 728 insertions(+), 239 deletions(-) diff --git a/src/addon/mod/assign/classes/base-feedback-handler.ts b/src/addon/mod/assign/classes/base-feedback-handler.ts index 33e08c2d4..a63a11a82 100644 --- a/src/addon/mod/assign/classes/base-feedback-handler.ts +++ b/src/addon/mod/assign/classes/base-feedback-handler.ts @@ -15,6 +15,7 @@ import { Injector } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { AddonModAssignFeedbackHandler } from '../providers/feedback-delegate'; +import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin } from '../providers/assign'; /** * Base handler for feedback plugins. @@ -48,7 +49,7 @@ export class AddonModAssignBaseFeedbackHandler implements AddonModAssignFeedback * @param plugin The plugin object. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin): any | Promise { // Nothing to do. } @@ -74,7 +75,8 @@ export class AddonModAssignBaseFeedbackHandler implements AddonModAssignFeedback * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise { return []; } @@ -84,7 +86,7 @@ export class AddonModAssignBaseFeedbackHandler implements AddonModAssignFeedback * @param plugin The plugin object. * @return The plugin name. */ - getPluginName(plugin: any): string { + getPluginName(plugin: AddonModAssignPlugin): string { // Check if there's a translated string for the plugin. const translationId = 'addon.mod_assign_feedback_' + plugin.type + '.pluginname', translation = this.translate.instant(translationId); @@ -109,7 +111,8 @@ export class AddonModAssignBaseFeedbackHandler implements AddonModAssignFeedback * @param inputData Data entered by the user for the feedback. * @return Boolean (or promise resolved with boolean): whether the data has changed. */ - hasDataChanged(assign: any, submission: any, plugin: any, inputData: any): boolean | Promise { + hasDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, userId: number): boolean | Promise { return false; } @@ -144,7 +147,8 @@ export class AddonModAssignBaseFeedbackHandler implements AddonModAssignFeedback * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - prefetch(assign: any, submission: any, plugin: any, siteId?: string): Promise { + prefetch(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): Promise { return Promise.resolve(); } @@ -158,7 +162,8 @@ export class AddonModAssignBaseFeedbackHandler implements AddonModAssignFeedback * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareFeedbackData(assignId: number, userId: number, plugin: any, pluginData: any, siteId?: string): void | Promise { + prepareFeedbackData(assignId: number, userId: number, plugin: AddonModAssignPlugin, pluginData: any, + siteId?: string): void | Promise { // Nothing to do. } @@ -172,7 +177,8 @@ export class AddonModAssignBaseFeedbackHandler implements AddonModAssignFeedback * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - saveDraft(assignId: number, userId: number, plugin: any, data: any, siteId?: string): void | Promise { + saveDraft(assignId: number, userId: number, plugin: AddonModAssignPlugin, data: any, siteId?: string) + : void | Promise { // Nothing to do. } } diff --git a/src/addon/mod/assign/classes/base-submission-handler.ts b/src/addon/mod/assign/classes/base-submission-handler.ts index e0e6bb34e..1c34ce157 100644 --- a/src/addon/mod/assign/classes/base-submission-handler.ts +++ b/src/addon/mod/assign/classes/base-submission-handler.ts @@ -15,6 +15,7 @@ import { Injector } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { AddonModAssignSubmissionHandler } from '../providers/submission-delegate'; +import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin } from '../providers/assign'; /** * Base handler for submission plugins. @@ -38,7 +39,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param plugin The plugin object. * @return Boolean or promise resolved with boolean: whether it can be edited in offline. */ - canEditOffline(assign: any, submission: any, plugin: any): boolean | Promise { + canEditOffline(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin): boolean | Promise { return false; } @@ -50,7 +52,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param plugin The plugin object. * @param inputData Data entered by the user for the submission. */ - clearTmpData(assign: any, submission: any, plugin: any, inputData: any): void { + clearTmpData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): void { // Nothing to do. } @@ -65,7 +68,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - copySubmissionData(assign: any, plugin: any, pluginData: any, userId?: number, siteId?: string): void | Promise { + copySubmissionData(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin, pluginData: any, + userId?: number, siteId?: string): void | Promise { // Nothing to do. } @@ -79,7 +83,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - deleteOfflineData(assign: any, submission: any, plugin: any, offlineData: any, siteId?: string): void | Promise { + deleteOfflineData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, siteId?: string): void | Promise { // Nothing to do. } @@ -92,7 +97,7 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param edit Whether the user is editing. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any, edit?: boolean): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin, edit?: boolean): any | Promise { // Nothing to do. } @@ -106,7 +111,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise { return []; } @@ -116,7 +122,7 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param plugin The plugin object. * @return The plugin name. */ - getPluginName(plugin: any): string { + getPluginName(plugin: AddonModAssignPlugin): string { // Check if there's a translated string for the plugin. const translationId = 'addon.mod_assign_submission_' + plugin.type + '.pluginname', translation = this.translate.instant(translationId); @@ -139,7 +145,7 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param plugin The plugin object. * @return The size (or promise resolved with size). */ - getSizeForCopy(assign: any, plugin: any): number | Promise { + getSizeForCopy(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin): number | Promise { return 0; } @@ -147,10 +153,12 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * Get the size of data (in bytes) this plugin will send to add or edit a submission. * * @param assign The assignment. + * @param submission The submission. * @param plugin The plugin object. * @return The size (or promise resolved with size). */ - getSizeForEdit(assign: any, plugin: any): number | Promise { + getSizeForEdit(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): number | Promise { return 0; } @@ -163,7 +171,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param inputData Data entered by the user for the submission. * @return Boolean (or promise resolved with boolean): whether the data has changed. */ - hasDataChanged(assign: any, submission: any, plugin: any, inputData: any): boolean | Promise { + hasDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): boolean | Promise { return false; } @@ -194,7 +203,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - prefetch(assign: any, submission: any, plugin: any, siteId?: string): Promise { + prefetch?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): Promise { return Promise.resolve(); } @@ -211,7 +221,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSubmissionData?(assign: any, submission: any, plugin: any, inputData: any, pluginData: any, offline?: boolean, + prepareSubmissionData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, pluginData: any, offline?: boolean, userId?: number, siteId?: string): void | Promise { // Nothing to do. } @@ -228,8 +239,8 @@ export class AddonModAssignBaseSubmissionHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSyncData?(assign: any, submission: any, plugin: any, offlineData: any, pluginData: any, siteId?: string) - : void | Promise { + prepareSyncData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, pluginData: any, siteId?: string): void | Promise { // Nothing to do. } } diff --git a/src/addon/mod/assign/classes/feedback-plugin-component.ts b/src/addon/mod/assign/classes/feedback-plugin-component.ts index d315d1b7f..0076ba466 100644 --- a/src/addon/mod/assign/classes/feedback-plugin-component.ts +++ b/src/addon/mod/assign/classes/feedback-plugin-component.ts @@ -14,14 +14,15 @@ import { Input } from '@angular/core'; import { ModalController } from 'ionic-angular'; +import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin } from '../providers/assign'; /** * Base class for component to render a feedback plugin. */ export class AddonModAssignFeedbackPluginComponentBase { - @Input() assign: any; // The assignment. - @Input() submission: any; // The submission. - @Input() plugin: any; // The plugin object. + @Input() assign: AddonModAssignAssign; // The assignment. + @Input() submission: AddonModAssignSubmission; // The submission. + @Input() plugin: AddonModAssignPlugin; // The plugin object. @Input() userId: number; // The user ID of the submission. @Input() configs: any; // The configs for the plugin. @Input() canEdit: boolean; // Whether the user can edit. diff --git a/src/addon/mod/assign/classes/submission-plugin-component.ts b/src/addon/mod/assign/classes/submission-plugin-component.ts index 39e8cdd2b..552657b9d 100644 --- a/src/addon/mod/assign/classes/submission-plugin-component.ts +++ b/src/addon/mod/assign/classes/submission-plugin-component.ts @@ -13,15 +13,16 @@ // limitations under the License. import { Input } from '@angular/core'; +import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin } from '../providers/assign'; /** * Base class for component to render a submission plugin. */ export class AddonModAssignSubmissionPluginComponent { - @Input() assign: any; // The assignment. - @Input() submission: any; // The submission. - @Input() plugin: any; // The plugin object. - @Input() configs: any; // The configs for the plugin. + @Input() assign: AddonModAssignAssign; // The assignment. + @Input() submission: AddonModAssignSubmission; // The submission. + @Input() plugin: AddonModAssignPlugin; // The plugin object. + @Input() configs: {[name: string]: string}; // The configs for the plugin. @Input() edit: boolean; // Whether the user is editing. @Input() allowOffline: boolean; // Whether to allow offline. diff --git a/src/addon/mod/assign/components/feedback-plugin/feedback-plugin.ts b/src/addon/mod/assign/components/feedback-plugin/feedback-plugin.ts index 94b847fda..d28973ae8 100644 --- a/src/addon/mod/assign/components/feedback-plugin/feedback-plugin.ts +++ b/src/addon/mod/assign/components/feedback-plugin/feedback-plugin.ts @@ -13,7 +13,9 @@ // limitations under the License. import { Component, Input, OnInit, Injector, ViewChild } from '@angular/core'; -import { AddonModAssignProvider } from '../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../providers/assign'; import { AddonModAssignHelperProvider } from '../../providers/helper'; import { AddonModAssignFeedbackDelegate } from '../../providers/feedback-delegate'; import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component'; @@ -28,9 +30,9 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp export class AddonModAssignFeedbackPluginComponent implements OnInit { @ViewChild(CoreDynamicComponent) dynamicComponent: CoreDynamicComponent; - @Input() assign: any; // The assignment. - @Input() submission: any; // The submission. - @Input() plugin: any; // The plugin object. + @Input() assign: AddonModAssignAssign; // The assignment. + @Input() submission: AddonModAssignSubmission; // The submission. + @Input() plugin: AddonModAssignPlugin; // The plugin object. @Input() userId: number; // The user ID of the submission. @Input() canEdit: boolean | string; // Whether the user can edit. @Input() edit: boolean | string; // Whether the user is editing. diff --git a/src/addon/mod/assign/components/index/index.ts b/src/addon/mod/assign/components/index/index.ts index 2697f6c36..0361570eb 100644 --- a/src/addon/mod/assign/components/index/index.ts +++ b/src/addon/mod/assign/components/index/index.ts @@ -17,7 +17,7 @@ import { Content, NavController } from 'ionic-angular'; import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; -import { AddonModAssignProvider } from '../../providers/assign'; +import { AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmissionGradingSummary } from '../../providers/assign'; import { AddonModAssignHelperProvider } from '../../providers/helper'; import { AddonModAssignOfflineProvider } from '../../providers/assign-offline'; import { AddonModAssignSyncProvider } from '../../providers/assign-sync'; @@ -36,13 +36,13 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo component = AddonModAssignProvider.COMPONENT; moduleName = 'assign'; - assign: any; // The assign object. + assign: AddonModAssignAssign; // The assign object. canViewAllSubmissions: boolean; // Whether the user can view all submissions. canViewOwnSubmission: boolean; // Whether the user can view their own submission. timeRemaining: string; // Message about time remaining to submit. lateSubmissions: string; // Message about late submissions. showNumbers = true; // Whether to show number of submissions with each status. - summary: any; // The summary. + summary: AddonModAssignSubmissionGradingSummary; // The grading summary. needsGradingAvalaible: boolean; // Whether we can see the submissions that need grading. groupInfo: CoreGroupInfo = { @@ -153,7 +153,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo this.assign = assignData; this.dataRetrieved.emit(this.assign); - this.description = this.assign.intro || this.description; + this.description = this.assign.intro; if (sync) { // Try to synchronize the assign. diff --git a/src/addon/mod/assign/components/submission-plugin/submission-plugin.ts b/src/addon/mod/assign/components/submission-plugin/submission-plugin.ts index f8ba6d005..de2d664aa 100644 --- a/src/addon/mod/assign/components/submission-plugin/submission-plugin.ts +++ b/src/addon/mod/assign/components/submission-plugin/submission-plugin.ts @@ -13,7 +13,9 @@ // limitations under the License. import { Component, Input, OnInit, Injector, ViewChild } from '@angular/core'; -import { AddonModAssignProvider } from '../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../providers/assign'; import { AddonModAssignHelperProvider } from '../../providers/helper'; import { AddonModAssignSubmissionDelegate } from '../../providers/submission-delegate'; import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component'; @@ -28,9 +30,9 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp export class AddonModAssignSubmissionPluginComponent implements OnInit { @ViewChild(CoreDynamicComponent) dynamicComponent: CoreDynamicComponent; - @Input() assign: any; // The assignment. - @Input() submission: any; // The submission. - @Input() plugin: any; // The plugin object. + @Input() assign: AddonModAssignAssign; // The assignment. + @Input() submission: AddonModAssignSubmission; // The submission. + @Input() plugin: AddonModAssignPlugin; // The plugin object. @Input() edit: boolean | string; // Whether the user is editing. @Input() allowOffline: boolean | string; // Whether to allow offline. diff --git a/src/addon/mod/assign/components/submission/submission.ts b/src/addon/mod/assign/components/submission/submission.ts index 762270fb6..b5fa53729 100644 --- a/src/addon/mod/assign/components/submission/submission.ts +++ b/src/addon/mod/assign/components/submission/submission.ts @@ -29,7 +29,10 @@ import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreFileUploaderHelperProvider } from '@core/fileuploader/providers/helper'; import { CoreGradesHelperProvider } from '@core/grades/providers/helper'; import { CoreUserProvider } from '@core/user/providers/user'; -import { AddonModAssignProvider } from '../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmissionFeedback, AddonModAssignSubmission, + AddonModAssignSubmissionAttempt, AddonModAssignSubmissionPreviousAttempt, AddonModAssignPlugin +} from '../../providers/assign'; import { AddonModAssignHelperProvider } from '../../providers/helper'; import { AddonModAssignOfflineProvider } from '../../providers/assign-offline'; import { CoreTabsComponent } from '@components/tabs/tabs'; @@ -55,11 +58,11 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { loaded: boolean; // Whether data has been loaded. selectedTab: number; // Tab selected on start. - assign: any; // The assignment the submission belongs to. - userSubmission: any; // The submission object. + assign: AddonModAssignAssign; // The assignment the submission belongs to. + userSubmission: AddonModAssignSubmission; // The submission object. isSubmittedForGrading: boolean; // Whether the submission has been submitted for grading. submitModel: any = {}; // Model where to store the data to submit (for grading). - feedback: any; // The feedback. + feedback: AddonModAssignSubmissionFeedbackFormatted; // The feedback. hasOffline: boolean; // Whether there is offline data. submittedOffline: boolean; // Whether it was submitted in offline. fromDate: string; // Readable date when the assign started accepting submissions. @@ -67,7 +70,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { maxAttemptsText: string; // The text for maximum attempts. blindMarking: boolean; // Whether blind marking is enabled. user: any; // The user. - lastAttempt: any; // The last attempt. + lastAttempt: AddonModAssignSubmissionAttemptFormatted; // The last attempt. membersToSubmit: any[]; // Team members that need to submit the assignment. canSubmit: boolean; // Whether the user can submit for grading. canEdit: boolean; // Whether the user can edit the submission. @@ -77,7 +80,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { gradingStatusTranslationId: string; // Key of the text to display for the grading status. gradingColor: string; // Color to apply to the grading status. workflowStatusTranslationId: string; // Key of the text to display for the workflow status. - submissionPlugins: string[]; // List of submission plugins names. + submissionPlugins: AddonModAssignPlugin[]; // List of submission plugins. timeRemaining: string; // Message about time remaining. timeRemainingClass: string; // Class to apply to time remaining message. statusTranslated: string; // Status. @@ -99,7 +102,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { protected siteId: string; // Current site ID. protected currentUserId: number; // Current user ID. - protected previousAttempt: any; // The previous attempt. + protected previousAttempt: AddonModAssignSubmissionPreviousAttempt; // The previous attempt. protected submissionStatusAvailable: boolean; // Whether we were able to retrieve the submission status. protected originalGrades: any = {}; // Object with the original grade data, to check for changes. protected isDestroyed: boolean; // Whether the component has been destroyed. @@ -209,7 +212,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { return this.goToEdit(); } - const previousSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, this.previousAttempt); + const previousSubmission = this.previousAttempt.submission; let modal = this.domUtils.showModalLoading(); this.assignHelper.getSubmissionSizeForCopy(this.assign, previousSubmission).catch(() => { @@ -303,7 +306,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { } if (this.feedback && this.feedback.plugins) { - return this.assignHelper.hasFeedbackDataChanged(this.assign, this.submitId, this.feedback).catch(() => { + return this.assignHelper.hasFeedbackDataChanged(this.assign, this.userSubmission, this.feedback, this.submitId) + .catch(() => { // Error ocurred, consider there are no changes. return false; }); @@ -438,7 +442,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { // Check if there's any unsupported plugin for editing. if (!this.userSubmission || !this.userSubmission.plugins) { // Submission not created yet, we have to use assign configs to detect the plugins used. - this.userSubmission = {}; + this.userSubmission = this.assignHelper.createEmptySubmission(); this.userSubmission.plugins = this.assignHelper.getPluginsEnabled(this.assign, 'assignsubmission'); } @@ -461,7 +465,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { * @param feedback The feedback data from the submission status. * @return Promise resolved when done. */ - protected loadFeedback(feedback: any): Promise { + protected loadFeedback(feedback: AddonModAssignSubmissionFeedback): Promise { this.grade = { method: false, grade: false, @@ -571,7 +575,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { if (!this.feedback || !this.feedback.plugins) { // Feedback plugins not present, we have to use assign configs to detect the plugins used. - this.feedback = {}; + this.feedback = this.assignHelper.createEmptyFeedback(); this.feedback.plugins = this.assignHelper.getPluginsEnabled(this.assign, 'assignfeedback'); } @@ -885,7 +889,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { // Show error if submission statement should be shown but it couldn't be retrieved. this.showErrorStatementEdit = submissionStatementMissing && !this.assign.submissiondrafts && this.submitId == this.currentUserId; - this.showErrorStatementSubmit = submissionStatementMissing && this.assign.submissiondrafts; + this.showErrorStatementSubmit = submissionStatementMissing && !!this.assign.submissiondrafts; this.userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, response.lastattempt); @@ -954,3 +958,17 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { } } } + +/** + * Submission attempt with some calculated data. + */ +type AddonModAssignSubmissionAttemptFormatted = AddonModAssignSubmissionAttempt & { + submissiongroupname?: string; // Calculated in the app. Group name the attempt belongs to. +}; + +/** + * Feedback of an assign submission with some calculated data. + */ +type AddonModAssignSubmissionFeedbackFormatted = AddonModAssignSubmissionFeedback & { + advancedgrade?: boolean; // Calculated in the app. Whether it uses advanced grading. +}; diff --git a/src/addon/mod/assign/feedback/comments/providers/handler.ts b/src/addon/mod/assign/feedback/comments/providers/handler.ts index ef4e1655b..1533fd67d 100644 --- a/src/addon/mod/assign/feedback/comments/providers/handler.ts +++ b/src/addon/mod/assign/feedback/comments/providers/handler.ts @@ -16,7 +16,9 @@ import { Injectable, Injector } from '@angular/core'; import { CoreSitesProvider } from '@providers/sites'; import { CoreTextUtilsProvider } from '@providers/utils/text'; -import { AddonModAssignProvider } from '../../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../../providers/assign'; import { AddonModAssignOfflineProvider } from '../../../providers/assign-offline'; import { AddonModAssignFeedbackHandler } from '../../../providers/feedback-delegate'; import { AddonModAssignFeedbackCommentsComponent } from '../component/comments'; @@ -50,14 +52,14 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed } /** - * Return the Component to use to display the plugin data, either in read or in edit mode. + * Return the Component to use to display the plugin data. * It's recommended to return the class of the component, but you can also return an instance of the component. * * @param injector Injector. * @param plugin The plugin object. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin): any | Promise { return AddonModAssignFeedbackCommentsComponent; } @@ -101,7 +103,8 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise { return this.assignProvider.getSubmissionPluginAttachments(plugin); } @@ -135,7 +138,9 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed * @param userId User ID of the submission. * @return Boolean (or promise resolved with boolean): whether the data has changed. */ - hasDataChanged(assign: any, submission: any, plugin: any, inputData: any, userId: number): boolean | Promise { + hasDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, userId: number): boolean | Promise { + // Get it from plugin or offline. return this.assignOfflineProvider.getSubmissionGrade(assign.id, userId).catch(() => { // No offline data found. @@ -191,7 +196,9 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareFeedbackData(assignId: number, userId: number, plugin: any, pluginData: any, siteId?: string): void | Promise { + prepareFeedbackData(assignId: number, userId: number, plugin: AddonModAssignPlugin, pluginData: any, + siteId?: string): void | Promise { + const draft = this.getDraft(assignId, userId, siteId); if (draft) { @@ -212,7 +219,9 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - saveDraft(assignId: number, userId: number, plugin: any, data: any, siteId?: string): void | Promise { + saveDraft(assignId: number, userId: number, plugin: AddonModAssignPlugin, data: any, siteId?: string) + : void | Promise { + if (data) { this.drafts[this.getDraftId(assignId, userId, siteId)] = data; } diff --git a/src/addon/mod/assign/feedback/editpdf/providers/handler.ts b/src/addon/mod/assign/feedback/editpdf/providers/handler.ts index 45276e932..5b2f8e0ef 100644 --- a/src/addon/mod/assign/feedback/editpdf/providers/handler.ts +++ b/src/addon/mod/assign/feedback/editpdf/providers/handler.ts @@ -14,7 +14,9 @@ // limitations under the License. import { Injectable, Injector } from '@angular/core'; -import { AddonModAssignProvider } from '../../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../../providers/assign'; import { AddonModAssignFeedbackHandler } from '../../../providers/feedback-delegate'; import { AddonModAssignFeedbackEditPdfComponent } from '../component/editpdf'; @@ -29,14 +31,14 @@ export class AddonModAssignFeedbackEditPdfHandler implements AddonModAssignFeedb constructor(private assignProvider: AddonModAssignProvider) { } /** - * Return the Component to use to display the plugin data, either in read or in edit mode. + * Return the Component to use to display the plugin data. * It's recommended to return the class of the component, but you can also return an instance of the component. * * @param injector Injector. * @param plugin The plugin object. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin): any | Promise { return AddonModAssignFeedbackEditPdfComponent; } @@ -50,7 +52,8 @@ export class AddonModAssignFeedbackEditPdfHandler implements AddonModAssignFeedb * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise { return this.assignProvider.getSubmissionPluginAttachments(plugin); } diff --git a/src/addon/mod/assign/feedback/file/providers/handler.ts b/src/addon/mod/assign/feedback/file/providers/handler.ts index 2d55cc35d..adc6da09d 100644 --- a/src/addon/mod/assign/feedback/file/providers/handler.ts +++ b/src/addon/mod/assign/feedback/file/providers/handler.ts @@ -14,7 +14,9 @@ // limitations under the License. import { Injectable, Injector } from '@angular/core'; -import { AddonModAssignProvider } from '../../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../../providers/assign'; import { AddonModAssignFeedbackHandler } from '../../../providers/feedback-delegate'; import { AddonModAssignFeedbackFileComponent } from '../component/file'; @@ -29,14 +31,14 @@ export class AddonModAssignFeedbackFileHandler implements AddonModAssignFeedback constructor(private assignProvider: AddonModAssignProvider) { } /** - * Return the Component to use to display the plugin data, either in read or in edit mode. + * Return the Component to use to display the plugin data. * It's recommended to return the class of the component, but you can also return an instance of the component. * * @param injector Injector. * @param plugin The plugin object. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin): any | Promise { return AddonModAssignFeedbackFileComponent; } @@ -50,7 +52,8 @@ export class AddonModAssignFeedbackFileHandler implements AddonModAssignFeedback * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise { return this.assignProvider.getSubmissionPluginAttachments(plugin); } diff --git a/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts b/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts index 3c60de76e..ace3043c0 100644 --- a/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts +++ b/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts @@ -17,6 +17,9 @@ import { IonicPage, ViewController, NavParams } from 'ionic-angular'; import { TranslateService } from '@ngx-translate/core'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { AddonModAssignFeedbackDelegate } from '../../providers/feedback-delegate'; +import { + AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../providers/assign'; /** * Modal that allows editing a feedback plugin. @@ -28,9 +31,9 @@ import { AddonModAssignFeedbackDelegate } from '../../providers/feedback-delegat }) export class AddonModAssignEditFeedbackModalPage { - @Input() assign: any; // The assignment. - @Input() submission: any; // The submission. - @Input() plugin: any; // The plugin object. + @Input() assign: AddonModAssignAssign; // The assignment. + @Input() submission: AddonModAssignSubmission; // The submission. + @Input() plugin: AddonModAssignPlugin; // The plugin object. @Input() userId: number; // The user ID of the submission. protected forceLeave = false; // To allow leaving the page without checking for changes. @@ -99,8 +102,8 @@ export class AddonModAssignEditFeedbackModalPage { * @return Promise resolved with boolean: whether the data has changed. */ protected hasDataChanged(): Promise { - return this.feedbackDelegate.hasPluginDataChanged(this.assign, this.userId, this.plugin, this.getInputData(), this.userId) - .catch(() => { + return this.feedbackDelegate.hasPluginDataChanged(this.assign, this.submission, this.plugin, this.getInputData(), + this.userId).catch(() => { // Ignore errors. return true; }); diff --git a/src/addon/mod/assign/pages/edit/edit.ts b/src/addon/mod/assign/pages/edit/edit.ts index 51f72b0a6..f8569eb0f 100644 --- a/src/addon/mod/assign/pages/edit/edit.ts +++ b/src/addon/mod/assign/pages/edit/edit.ts @@ -20,7 +20,7 @@ import { CoreSitesProvider } from '@providers/sites'; import { CoreSyncProvider } from '@providers/sync'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreFileUploaderHelperProvider } from '@core/fileuploader/providers/helper'; -import { AddonModAssignProvider } from '../../providers/assign'; +import { AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission } from '../../providers/assign'; import { AddonModAssignOfflineProvider } from '../../providers/assign-offline'; import { AddonModAssignSyncProvider } from '../../providers/assign-sync'; import { AddonModAssignHelperProvider } from '../../providers/helper'; @@ -35,9 +35,9 @@ import { AddonModAssignHelperProvider } from '../../providers/helper'; }) export class AddonModAssignEditPage implements OnInit, OnDestroy { title: string; // Title to display. - assign: any; // Assignment. + assign: AddonModAssignAssign; // Assignment. courseId: number; // Course ID the assignment belongs to. - userSubmission: any; // The user submission. + userSubmission: AddonModAssignSubmission; // The user submission. allowOffline: boolean; // Whether offline is allowed. submissionStatement: string; // The submission statement. submissionStatementAccepted: boolean; // Whether submission statement is accepted. @@ -129,7 +129,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy { const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, response.lastattempt); // Check if the user can edit it in offline. - return this.assignHelper.canEditSubmissionOffline(this.assign, userSubmission).then((canEditOffline) => { + return this.assignHelper.canEditSubmissionOffline(this.assign, userSubmission).then((canEditOffline): any => { if (canEditOffline) { return response; } @@ -301,7 +301,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy { } else { // Try to send it to server. promise = this.assignProvider.saveSubmission(this.assign.id, this.courseId, pluginData, this.allowOffline, - this.userSubmission.timemodified, this.assign.submissiondrafts, this.userId); + this.userSubmission.timemodified, !!this.assign.submissiondrafts, this.userId); } return promise.then(() => { diff --git a/src/addon/mod/assign/pages/submission-list/submission-list.ts b/src/addon/mod/assign/pages/submission-list/submission-list.ts index 9cc87c045..c3a364b4d 100644 --- a/src/addon/mod/assign/pages/submission-list/submission-list.ts +++ b/src/addon/mod/assign/pages/submission-list/submission-list.ts @@ -19,9 +19,11 @@ import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups'; -import { AddonModAssignProvider } from '../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignGrade, AddonModAssignSubmission +} from '../../providers/assign'; import { AddonModAssignOfflineProvider } from '../../providers/assign-offline'; -import { AddonModAssignHelperProvider } from '../../providers/helper'; +import { AddonModAssignHelperProvider, AddonModAssignSubmissionFormatted } from '../../providers/helper'; import { CoreSplitViewComponent } from '@components/split-view/split-view'; /** @@ -36,7 +38,7 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent; title: string; // Title to display. - assign: any; // Assignment. + assign: AddonModAssignAssign; // Assignment. submissions: any[]; // List of submissions loaded: boolean; // Whether data has been loaded. haveAllParticipants: boolean; // Whether all participants have been loaded. @@ -53,7 +55,7 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { protected courseId: number; // Course ID the assignment belongs to. protected selectedStatus: string; // The status to see. protected gradedObserver; // Observer to refresh data when a grade changes. - protected submissionsData: any; + protected submissionsData: {canviewsubmissions: boolean, submissions?: AddonModAssignSubmission[]}; constructor(navParams: NavParams, protected sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, protected domUtils: CoreDomUtilsProvider, protected translate: TranslateService, @@ -161,14 +163,14 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { !this.assign.markingworkflow ? this.assignProvider.getAssignmentGrades(this.assign.id) : Promise.resolve(null), ]; - return Promise.all(promises).then(([submissions, grades]) => { + return Promise.all(promises).then(([submissions, grades]: [AddonModAssignSubmissionFormatted[], AddonModAssignGrade[]]) => { // Filter the submissions to get only the ones with the right status and add some extra data. const getNeedGrading = this.selectedStatus == AddonModAssignProvider.NEED_GRADING, searchStatus = getNeedGrading ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : this.selectedStatus, promises = [], showSubmissions = []; - submissions.forEach((submission) => { + submissions.forEach((submission: AddonModAssignSubmissionForList) => { if (!searchStatus || searchStatus == submission.status) { promises.push(this.assignOfflineProvider.getSubmissionGrade(this.assign.id, submission.userid).catch(() => { // Ignore errors. @@ -213,7 +215,7 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { submission.statusTranslated = this.translate.instant('addon.mod_assign.submissionstatus_' + submission.status); } else { - submission.statusTranslated = false; + submission.statusTranslated = ''; } if (notSynced) { @@ -224,7 +226,7 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { submission.gradingStatusTranslationId = this.assignProvider.getSubmissionGradingStatusTranslationId(submission.gradingstatus); } else { - submission.gradingStatusTranslationId = false; + submission.gradingStatusTranslationId = ''; } showSubmissions.push(submission); @@ -299,3 +301,13 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { this.gradedObserver && this.gradedObserver.off(); } } + +/** + * Calculated data for an assign submission. + */ +type AddonModAssignSubmissionForList = AddonModAssignSubmissionFormatted & { + statusColor?: string; // Calculated in the app. Color of the submission status. + gradingColor?: string; // Calculated in the app. Color of the submission grading status. + statusTranslated?: string; // Calculated in the app. Translated text of the submission status. + gradingStatusTranslationId?: string; // Calculated in the app. Key of the text of the submission grading status. +}; diff --git a/src/addon/mod/assign/pages/submission-review/submission-review.ts b/src/addon/mod/assign/pages/submission-review/submission-review.ts index a3652667d..9c96c1c07 100644 --- a/src/addon/mod/assign/pages/submission-review/submission-review.ts +++ b/src/addon/mod/assign/pages/submission-review/submission-review.ts @@ -17,7 +17,7 @@ import { IonicPage, NavController, NavParams } from 'ionic-angular'; import { CoreAppProvider } from '@providers/app'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreCourseProvider } from '@core/course/providers/course'; -import { AddonModAssignProvider } from '../../providers/assign'; +import { AddonModAssignProvider, AddonModAssignAssign } from '../../providers/assign'; import { AddonModAssignSubmissionComponent } from '../../components/submission/submission'; /** @@ -40,7 +40,7 @@ export class AddonModAssignSubmissionReviewPage implements OnInit { loaded: boolean; // Whether data has been loaded. canSaveGrades: boolean; // Whether the user can save grades. - protected assign: any; // The assignment the submission belongs to. + protected assign: AddonModAssignAssign; // The assignment the submission belongs to. protected blindMarking: boolean; // Whether it uses blind marking. protected forceLeave = false; // To allow leaving the page without checking for changes. diff --git a/src/addon/mod/assign/providers/assign-sync.ts b/src/addon/mod/assign/providers/assign-sync.ts index 60967dc07..c61e09cfa 100644 --- a/src/addon/mod/assign/providers/assign-sync.ts +++ b/src/addon/mod/assign/providers/assign-sync.ts @@ -26,7 +26,7 @@ import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper'; import { CoreGradesHelperProvider } from '@core/grades/providers/helper'; import { CoreSyncBaseProvider } from '@classes/base-sync'; -import { AddonModAssignProvider } from './assign'; +import { AddonModAssignProvider, AddonModAssignAssign } from './assign'; import { AddonModAssignOfflineProvider } from './assign-offline'; import { AddonModAssignSubmissionDelegate } from './submission-delegate'; @@ -169,14 +169,14 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider { syncAssign(assignId: number, siteId?: string): Promise { siteId = siteId || this.sitesProvider.getCurrentSiteId(); - const promises = [], + const promises: Promise[] = [], result: AddonModAssignSyncResult = { warnings: [], updated: false }; - let assign, - courseId, - syncPromise; + let assign: AddonModAssignAssign, + courseId: number, + syncPromise: Promise; if (this.isSyncing(assignId, siteId)) { // There's already a sync ongoing for this assign, return the promise. @@ -269,7 +269,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved if success, rejected otherwise. */ - protected syncSubmission(assign: any, offlineData: any, warnings: string[], siteId?: string): Promise { + protected syncSubmission(assign: AddonModAssignAssign, offlineData: any, warnings: string[], siteId?: string): Promise { const userId = offlineData.userid, pluginData = {}; let discardError, @@ -358,8 +358,8 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved if success, rejected otherwise. */ - protected syncSubmissionGrade(assign: any, offlineData: any, warnings: string[], courseId: number, siteId?: string) - : Promise { + protected syncSubmissionGrade(assign: AddonModAssignAssign, offlineData: any, warnings: string[], courseId: number, + siteId?: string): Promise { const userId = offlineData.userid; let discardError; diff --git a/src/addon/mod/assign/providers/assign.ts b/src/addon/mod/assign/providers/assign.ts index e819751a6..07a656c1a 100644 --- a/src/addon/mod/assign/providers/assign.ts +++ b/src/addon/mod/assign/providers/assign.ts @@ -27,6 +27,7 @@ import { AddonModAssignSubmissionDelegate } from './submission-delegate'; import { AddonModAssignOfflineProvider } from './assign-offline'; import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; import { CoreInterceptor } from '@classes/interceptor'; +import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws'; /** * Service that provides some functions for assign. @@ -123,7 +124,7 @@ export class AddonModAssignProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the assignment. */ - getAssignment(courseId: number, cmId: number, ignoreCache?: boolean, siteId?: string): Promise { + getAssignment(courseId: number, cmId: number, ignoreCache?: boolean, siteId?: string): Promise { return this.getAssignmentByField(courseId, 'cmid', cmId, ignoreCache, siteId); } @@ -138,7 +139,7 @@ export class AddonModAssignProvider { * @return Promise resolved when the assignment is retrieved. */ protected getAssignmentByField(courseId: number, key: string, value: any, ignoreCache?: boolean, siteId?: string) - : Promise { + : Promise { return this.sitesProvider.getSite(siteId).then((site) => { const params = { @@ -161,7 +162,7 @@ export class AddonModAssignProvider { delete params.includenotenrolledcourses; return site.read('mod_assign_get_assignments', params, preSets); - }).then((response) => { + }).then((response: AddonModAssignGetAssignmentsResult): any => { // Search the assignment to return. if (response.courses && response.courses.length) { const assignments = response.courses[0].assignments; @@ -187,7 +188,7 @@ export class AddonModAssignProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the assignment. */ - getAssignmentById(courseId: number, id: number, ignoreCache?: boolean, siteId?: string): Promise { + getAssignmentById(courseId: number, id: number, ignoreCache?: boolean, siteId?: string): Promise { return this.getAssignmentByField(courseId, 'id', id, ignoreCache, siteId); } @@ -225,7 +226,9 @@ export class AddonModAssignProvider { preSets.emergencyCache = false; } - return site.read('mod_assign_get_user_mappings', params, preSets).then((response) => { + return site.read('mod_assign_get_user_mappings', params, preSets) + .then((response: AddonModAssignGetUserMappingsResult): any => { + // Search the user. if (response.assignments && response.assignments.length) { if (!userId || userId < 0) { @@ -271,7 +274,7 @@ export class AddonModAssignProvider { * @param siteId Site ID. If not defined, current site. * @return Resolved with requested info when done. */ - getAssignmentGrades(assignId: number, ignoreCache?: boolean, siteId?: string): Promise { + getAssignmentGrades(assignId: number, ignoreCache?: boolean, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { const params = { assignmentids: [assignId] @@ -285,7 +288,7 @@ export class AddonModAssignProvider { preSets.emergencyCache = false; } - return site.read('mod_assign_get_grades', params, preSets).then((response) => { + return site.read('mod_assign_get_grades', params, preSets).then((response: AddonModAssignGetGradesResult): any => { // Search the assignment. if (response.assignments && response.assignments.length) { const assignment = response.assignments[0]; @@ -294,7 +297,7 @@ export class AddonModAssignProvider { return assignment.grades; } } else if (response.warnings && response.warnings.length) { - if (response.warnings[0].warningcode == 3) { + if (response.warnings[0].warningcode == '3') { // No grades found. return []; } @@ -362,7 +365,9 @@ export class AddonModAssignProvider { * @param attempt Attempt. * @return Submission object or null. */ - getSubmissionObjectFromAttempt(assign: any, attempt: any): any { + getSubmissionObjectFromAttempt(assign: AddonModAssignAssign, attempt: AddonModAssignSubmissionAttempt) + : AddonModAssignSubmission { + if (!attempt) { return null; } @@ -432,7 +437,7 @@ export class AddonModAssignProvider { * @return Promise resolved when done. */ getSubmissions(assignId: number, ignoreCache?: boolean, siteId?: string) - : Promise<{canviewsubmissions: boolean, submissions?: any[]}> { + : Promise<{canviewsubmissions: boolean, submissions?: AddonModAssignSubmission[]}> { return this.sitesProvider.getSite(siteId).then((site) => { const params = { @@ -448,9 +453,11 @@ export class AddonModAssignProvider { preSets.emergencyCache = false; } - return site.read('mod_assign_get_submissions', params, preSets).then((response): any => { + return site.read('mod_assign_get_submissions', params, preSets) + .then((response: AddonModAssignGetSubmissionsResult): any => { + // Check if we can view submissions, with enough permissions. - if (response.warnings.length > 0 && response.warnings[0].warningcode == 1) { + if (response.warnings.length > 0 && response.warnings[0].warningcode == '1') { return {canviewsubmissions: false}; } @@ -489,7 +496,7 @@ export class AddonModAssignProvider { * @return Promise always resolved with the user submission status. */ getSubmissionStatus(assignId: number, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true, - ignoreCache?: boolean, siteId?: string): Promise { + ignoreCache?: boolean, siteId?: string): Promise { userId = userId || 0; @@ -540,7 +547,7 @@ export class AddonModAssignProvider { * @return Promise always resolved with the user submission status. */ getSubmissionStatusWithRetry(assign: any, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true, - ignoreCache?: boolean, siteId?: string): Promise { + ignoreCache?: boolean, siteId?: string): Promise { return this.getSubmissionStatus(assign.id, userId, groupId, isBlind, filter, ignoreCache, siteId).then((response) => { const userSubmission = this.getSubmissionObjectFromAttempt(assign, response.lastattempt); @@ -630,7 +637,9 @@ export class AddonModAssignProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the list of participants and summary of submissions. */ - listParticipants(assignId: number, groupId?: number, ignoreCache?: boolean, siteId?: string): Promise { + listParticipants(assignId: number, groupId?: number, ignoreCache?: boolean, siteId?: string) + : Promise { + groupId = groupId || 0; return this.sitesProvider.getSite(siteId).then((site) => { @@ -1051,14 +1060,14 @@ export class AddonModAssignProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when saved, rejected otherwise. */ - saveSubmissionOnline(assignId: number, pluginData: any, siteId?: string): Promise { + saveSubmissionOnline(assignId: number, pluginData: any, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { const params = { assignmentid: assignId, plugindata: pluginData }; - return site.write('mod_assign_save_submission', params).then((warnings) => { + return site.write('mod_assign_save_submission', params).then((warnings: CoreWSExternalWarning[]) => { if (warnings && warnings.length) { // The WebService returned warnings, reject. return Promise.reject(warnings[0]); @@ -1120,14 +1129,14 @@ export class AddonModAssignProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when submitted, rejected otherwise. */ - submitForGradingOnline(assignId: number, acceptStatement: boolean, siteId?: string): Promise { + submitForGradingOnline(assignId: number, acceptStatement: boolean, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { const params = { assignmentid: assignId, acceptsubmissionstatement: acceptStatement ? 1 : 0 }; - return site.write('mod_assign_submit_for_grading', params).then((warnings) => { + return site.write('mod_assign_submit_for_grading', params).then((warnings: CoreWSExternalWarning[]) => { if (warnings && warnings.length) { // The WebService returned warnings, reject. return Promise.reject(warnings[0]); @@ -1169,7 +1178,10 @@ export class AddonModAssignProvider { return this.isGradingOfflineEnabled(siteId).then((enabled) => { if (!enabled) { return this.submitGradingFormOnline(assignId, userId, grade, attemptNumber, addAttempt, workflowState, - applyToAll, outcomes, pluginData, siteId); + applyToAll, outcomes, pluginData, siteId).then(() => { + + return true; + }); } if (!this.appProvider.isOnline()) { @@ -1212,7 +1224,7 @@ export class AddonModAssignProvider { * @return Promise resolved when submitted, rejected otherwise. */ submitGradingFormOnline(assignId: number, userId: number, grade: number, attemptNumber: number, addAttempt: boolean, - workflowState: string, applyToAll: boolean, outcomes: any, pluginData: any, siteId?: string): Promise { + workflowState: string, applyToAll: boolean, outcomes: any, pluginData: any, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { userId = userId || site.getUserId(); @@ -1243,7 +1255,7 @@ export class AddonModAssignProvider { jsonformdata: JSON.stringify(serialized) }; - return site.write('mod_assign_submit_grading_form', params).then((warnings) => { + return site.write('mod_assign_submit_grading_form', params).then((warnings: CoreWSExternalWarning[]) => { if (warnings && warnings.length) { // The WebService returned warnings, reject. return Promise.reject(warnings[0]); @@ -1271,3 +1283,285 @@ export class AddonModAssignProvider { }); } } + +/** + * Assign data returned by mod_assign_get_assignments. + */ +export type AddonModAssignAssign = { + id: number; // Assignment id. + cmid: number; // Course module id. + course: number; // Course id. + name: string; // Assignment name. + nosubmissions: number; // No submissions. + submissiondrafts: number; // Submissions drafts. + sendnotifications: number; // Send notifications. + sendlatenotifications: number; // Send notifications. + sendstudentnotifications: number; // Send student notifications (default). + duedate: number; // Assignment due date. + allowsubmissionsfromdate: number; // Allow submissions from date. + grade: number; // Grade type. + timemodified: number; // Last time assignment was modified. + completionsubmit: number; // If enabled, set activity as complete following submission. + cutoffdate: number; // Date after which submission is not accepted without an extension. + gradingduedate?: number; // @since 3.3. The expected date for marking the submissions. + teamsubmission: number; // If enabled, students submit as a team. + requireallteammemberssubmit: number; // If enabled, all team members must submit. + teamsubmissiongroupingid: number; // The grouping id for the team submission groups. + blindmarking: number; // If enabled, hide identities until reveal identities actioned. + hidegrader?: number; // @since 3.7. If enabled, hide grader to student. + revealidentities: number; // Show identities for a blind marking assignment. + attemptreopenmethod: string; // Method used to control opening new attempts. + maxattempts: number; // Maximum number of attempts allowed. + markingworkflow: number; // Enable marking workflow. + markingallocation: number; // Enable marking allocation. + requiresubmissionstatement: number; // Student must accept submission statement. + preventsubmissionnotingroup?: number; // @since 3.2. Prevent submission not in group. + submissionstatement?: string; // @since 3.2. Submission statement formatted. + submissionstatementformat?: number; // @since 3.2. Submissionstatement format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN). + configs: AddonModAssignConfig[]; // Configuration settings. + intro?: string; // Assignment intro, not allways returned because it deppends on the activity configuration. + introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN). + introfiles?: CoreWSExternalFile[]; // @since 3.2. + introattachments?: CoreWSExternalFile[]; +}; + +/** + * Config setting in an assign. + */ +export type AddonModAssignConfig = { + id?: number; // Assign_plugin_config id. + assignment?: number; // Assignment id. + plugin: string; // Plugin. + subtype: string; // Subtype. + name: string; // Name. + value: string; // Value. +}; + +/** + * Grade of an assign, returned by mod_assign_get_grades. + */ +export type AddonModAssignGrade = { + id: number; // Grade id. + assignment?: number; // Assignment id. + userid: number; // Student id. + attemptnumber: number; // Attempt number. + timecreated: number; // Grade creation time. + timemodified: number; // Grade last modified time. + grader: number; // Grader, -1 if grader is hidden. + grade: string; // Grade. + gradefordisplay?: string; // Grade rendered into a format suitable for display. +}; + +/** + * Assign submission returned by mod_assign_get_submissions. + */ +export type AddonModAssignSubmission = { + id: number; // Submission id. + userid: number; // Student id. + attemptnumber: number; // Attempt number. + timecreated: number; // Submission creation time. + timemodified: number; // Submission last modified time. + status: string; // Submission status. + groupid: number; // Group id. + assignment?: number; // Assignment id. + latest?: number; // Latest attempt. + plugins?: AddonModAssignPlugin[]; // Plugins. + gradingstatus?: string; // @since 3.2. Grading status. +}; + +/** + * Assign plugin. + */ +export type AddonModAssignPlugin = { + type: string; // Submission plugin type. + name: string; // Submission plugin name. + fileareas?: { // Fileareas. + area: string; // File area. + files?: CoreWSExternalFile[]; + }[]; + editorfields?: { // Editorfields. + name: string; // Field name. + description: string; // Field description. + text: string; // Field value. + format: number; // Text format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN). + }[]; +}; + +/** + * Grading summary of an assign submission. + */ +export type AddonModAssignSubmissionGradingSummary = { + participantcount: number; // Number of users who can submit. + submissiondraftscount: number; // Number of submissions in draft status. + submissionsenabled: boolean; // Whether submissions are enabled or not. + submissionssubmittedcount: number; // Number of submissions in submitted status. + submissionsneedgradingcount: number; // Number of submissions that need grading. + warnofungroupedusers: string; // Whether we need to warn people about groups. +}; + +/** + * Attempt of an assign submission. + */ +export type AddonModAssignSubmissionAttempt = { + submission?: AddonModAssignSubmission; // Submission info. + teamsubmission?: AddonModAssignSubmission; // Submission info. + submissiongroup?: number; // The submission group id (for group submissions only). + submissiongroupmemberswhoneedtosubmit?: number[]; // List of users who still need to submit (for group submissions only). + submissionsenabled: boolean; // Whether submissions are enabled or not. + locked: boolean; // Whether new submissions are locked. + graded: boolean; // Whether the submission is graded. + canedit: boolean; // Whether the user can edit the current submission. + caneditowner?: boolean; // @since 3.2. Whether the owner of the submission can edit it. + cansubmit: boolean; // Whether the user can submit. + extensionduedate: number; // Extension due date. + blindmarking: boolean; // Whether blind marking is enabled. + gradingstatus: string; // Grading status. + usergroups: number[]; // User groups in the course. +}; + +/** + * Previous attempt of an assign submission. + */ +export type AddonModAssignSubmissionPreviousAttempt = { + attemptnumber: number; // Attempt number. + submission?: AddonModAssignSubmission; // Submission info. + grade?: AddonModAssignGrade; // Grade information. + feedbackplugins?: AddonModAssignPlugin[]; // Feedback info. +}; + +/** + * Feedback of an assign submission. + */ +export type AddonModAssignSubmissionFeedback = { + grade: AddonModAssignGrade; // Grade information. + gradefordisplay: string; // Grade rendered into a format suitable for display. + gradeddate: number; // The date the user was graded. + plugins?: AddonModAssignPlugin[]; // Plugins info. +}; + +/** + * Participant returned by mod_assign_list_participants. + */ +export type AddonModAssignParticipant = { + id: number; // ID of the user. + username?: string; // The username. + firstname?: string; // The first name(s) of the user. + lastname?: string; // The family name of the user. + fullname: string; // The fullname of the user. + email?: string; // Email address. + address?: string; // Postal address. + phone1?: string; // Phone 1. + phone2?: string; // Phone 2. + icq?: string; // Icq number. + skype?: string; // Skype id. + yahoo?: string; // Yahoo id. + aim?: string; // Aim id. + msn?: string; // Msn number. + department?: string; // Department. + institution?: string; // Institution. + idnumber?: string; // The idnumber of the user. + interests?: string; // User interests (separated by commas). + firstaccess?: number; // First access to the site (0 if never). + lastaccess?: number; // Last access to the site (0 if never). + suspended?: boolean; // @since 3.2. Suspend user account, either false to enable user login or true to disable it. + description?: string; // User profile description. + descriptionformat?: number; // Int format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN). + city?: string; // Home city of the user. + url?: string; // URL of the user. + country?: string; // Home country code of the user, such as AU or CZ. + profileimageurlsmall?: string; // User image profile URL - small version. + profileimageurl?: string; // User image profile URL - big version. + customfields?: { // User custom fields (also known as user profile fields). + type: string; // The type of the custom field - text field, checkbox... + value: string; // The value of the custom field. + name: string; // The name of the custom field. + shortname: string; // The shortname of the custom field - to be able to build the field class in the code. + }[]; + preferences?: { // Users preferences. + name: string; // The name of the preferences. + value: string; // The value of the preference. + }[]; + recordid?: number; // @since 3.7. Record id. + groups?: { // User groups. + id: number; // Group id. + name: string; // Group name. + description: string; // Group description. + }[]; + roles?: { // User roles. + roleid: number; // Role id. + name: string; // Role name. + shortname: string; // Role shortname. + sortorder: number; // Role sortorder. + }[]; + enrolledcourses?: { // Courses where the user is enrolled - limited by which courses the user is able to see. + id: number; // Id of the course. + fullname: string; // Fullname of the course. + shortname: string; // Shortname of the course. + }[]; + submitted: boolean; // Have they submitted their assignment. + requiregrading: boolean; // Is their submission waiting for grading. + grantedextension?: boolean; // @since 3.3. Have they been granted an extension. + groupid?: number; // For group assignments this is the group id. + groupname?: string; // For group assignments this is the group name. +}; + +/** + * Result of WS mod_assign_get_assignments. + */ +export type AddonModAssignGetAssignmentsResult = { + courses: { // List of courses. + id: number; // Course id. + fullname: string; // Course full name. + shortname: string; // Course short name. + timemodified: number; // Last time modified. + assignments: AddonModAssignAssign[]; // Assignment info. + }[]; + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Result of WS mod_assign_get_user_mappings. + */ +export type AddonModAssignGetUserMappingsResult = { + assignments: { // List of assign user mapping data. + assignmentid: number; // Assignment id. + mappings: { + id: number; // User mapping id. + userid: number; // Student id. + }[]; + }[]; + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Result of WS mod_assign_get_grades. + */ +export type AddonModAssignGetGradesResult = { + assignments: { // List of assignment grade information. + assignmentid: number; // Assignment id. + grades: AddonModAssignGrade[]; + }[]; + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Result of WS mod_assign_get_submissions. + */ +export type AddonModAssignGetSubmissionsResult = { + assignments: { // Assignment submissions. + assignmentid: number; // Assignment id. + submissions: AddonModAssignSubmission[]; + }[]; + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Result of WS mod_assign_get_submission_status. + */ +export type AddonModAssignGetSubmissionStatusResult = { + gradingsummary?: AddonModAssignSubmissionGradingSummary; // Grading information. + lastattempt?: AddonModAssignSubmissionAttempt; // Last attempt information. + feedback?: AddonModAssignSubmissionFeedback; // Feedback for the last attempt. + previousattempts?: AddonModAssignSubmissionPreviousAttempt[]; // List all the previous attempts did by the user. + warnings?: CoreWSExternalWarning[]; +}; diff --git a/src/addon/mod/assign/providers/feedback-delegate.ts b/src/addon/mod/assign/providers/feedback-delegate.ts index c72dda969..4565f64be 100644 --- a/src/addon/mod/assign/providers/feedback-delegate.ts +++ b/src/addon/mod/assign/providers/feedback-delegate.ts @@ -18,6 +18,7 @@ import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { AddonModAssignDefaultFeedbackHandler } from './default-feedback-handler'; +import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin } from './assign'; /** * Interface that all feedback handlers must implement. @@ -47,7 +48,7 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler { * @param plugin The plugin object. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent?(injector: Injector, plugin: any): any | Promise; + getComponent?(injector: Injector, plugin: AddonModAssignPlugin): any | Promise; /** * Return the draft saved data of the feedback plugin. @@ -69,7 +70,8 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles?(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise; + getPluginFiles?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise; /** * Get a readable name to use for the plugin. @@ -77,7 +79,7 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler { * @param plugin The plugin object. * @return The plugin name. */ - getPluginName?(plugin: any): string; + getPluginName?(plugin: AddonModAssignPlugin): string; /** * Check if the feedback data has changed for this plugin. @@ -89,7 +91,8 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler { * @param userId User ID of the submission. * @return Boolean (or promise resolved with boolean): whether the data has changed. */ - hasDataChanged?(assign: any, submission: any, plugin: any, inputData: any, userId: number): boolean | Promise; + hasDataChanged?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, userId: number): boolean | Promise; /** * Check whether the plugin has draft data stored. @@ -111,7 +114,8 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - prefetch?(assign: any, submission: any, plugin: any, siteId?: string): Promise; + prefetch?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): Promise; /** * Prepare and add to pluginData the data to send to the server based on the draft data saved. @@ -123,7 +127,8 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareFeedbackData?(assignId: number, userId: number, plugin: any, pluginData: any, siteId?: string): void | Promise; + prepareFeedbackData?(assignId: number, userId: number, plugin: AddonModAssignPlugin, pluginData: any, + siteId?: string): void | Promise; /** * Save draft data of the feedback plugin. @@ -135,7 +140,8 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - saveDraft?(assignId: number, userId: number, plugin: any, data: any, siteId?: string): void | Promise; + saveDraft?(assignId: number, userId: number, plugin: AddonModAssignPlugin, data: any, siteId?: string) + : void | Promise; } /** @@ -160,7 +166,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - discardPluginFeedbackData(assignId: number, userId: number, plugin: any, siteId?: string): Promise { + discardPluginFeedbackData(assignId: number, userId: number, plugin: AddonModAssignPlugin, siteId?: string) + : Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'discardDraft', [assignId, userId, siteId])); } @@ -171,7 +178,7 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param plugin The plugin object. * @return Promise resolved with the component to use, undefined if not found. */ - getComponentForPlugin(injector: Injector, plugin: any): Promise { + getComponentForPlugin(injector: Injector, plugin: AddonModAssignPlugin): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'getComponent', [injector, plugin])); } @@ -184,7 +191,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the draft data. */ - getPluginDraftData(assignId: number, userId: number, plugin: any, siteId?: string): Promise { + getPluginDraftData(assignId: number, userId: number, plugin: AddonModAssignPlugin, siteId?: string) + : Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'getDraft', [assignId, userId, siteId])); } @@ -198,7 +206,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the files. */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'getPluginFiles', [assign, submission, plugin, siteId])); } @@ -208,7 +217,7 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param plugin Plugin to get the name for. * @return Human readable name. */ - getPluginName(plugin: any): string { + getPluginName(plugin: AddonModAssignPlugin): string { return this.executeFunctionOnEnabled(plugin.type, 'getPluginName', [plugin]); } @@ -222,7 +231,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param userId User ID of the submission. * @return Promise resolved with true if data has changed, resolved with false otherwise. */ - hasPluginDataChanged(assign: any, submission: any, plugin: any, inputData: any, userId: number): Promise { + hasPluginDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, userId: number): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'hasDataChanged', [assign, submission, plugin, inputData, userId])); } @@ -236,7 +246,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with true if it has draft data. */ - hasPluginDraftData(assignId: number, userId: number, plugin: any, siteId?: string): Promise { + hasPluginDraftData(assignId: number, userId: number, plugin: AddonModAssignPlugin, siteId?: string) + : Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'hasDraftData', [assignId, userId, siteId])); } @@ -259,7 +270,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - prefetch(assign: any, submission: any, plugin: any, siteId?: string): Promise { + prefetch(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, plugin: AddonModAssignPlugin, + siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'prefetch', [assign, submission, plugin, siteId])); } @@ -273,7 +285,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when data has been gathered. */ - preparePluginFeedbackData(assignId: number, userId: number, plugin: any, pluginData: any, siteId?: string): Promise { + preparePluginFeedbackData(assignId: number, userId: number, plugin: AddonModAssignPlugin, pluginData: any, + siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'prepareFeedbackData', [assignId, userId, plugin, pluginData, siteId])); @@ -289,7 +302,8 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when data has been saved. */ - saveFeedbackDraft(assignId: number, userId: number, plugin: any, inputData: any, siteId?: string): Promise { + saveFeedbackDraft(assignId: number, userId: number, plugin: AddonModAssignPlugin, inputData: any, + siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'saveDraft', [assignId, userId, plugin, inputData, siteId])); } diff --git a/src/addon/mod/assign/providers/helper.ts b/src/addon/mod/assign/providers/helper.ts index a634e520c..d89d14c97 100644 --- a/src/addon/mod/assign/providers/helper.ts +++ b/src/addon/mod/assign/providers/helper.ts @@ -21,7 +21,10 @@ import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader'; import { AddonModAssignFeedbackDelegate } from './feedback-delegate'; import { AddonModAssignSubmissionDelegate } from './submission-delegate'; -import { AddonModAssignProvider } from './assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignParticipant, + AddonModAssignSubmissionFeedback +} from './assign'; import { AddonModAssignOfflineProvider } from './assign-offline'; /** @@ -46,7 +49,7 @@ export class AddonModAssignHelperProvider { * @param submission Submission. * @return Whether it can be edited offline. */ - canEditSubmissionOffline(assign: any, submission: any): Promise { + canEditSubmissionOffline(assign: AddonModAssignAssign, submission: AddonModAssignSubmission): Promise { if (!submission) { return Promise.resolve(false); } @@ -81,7 +84,7 @@ export class AddonModAssignHelperProvider { * @param submission Submission to clear the data for. * @param inputData Data entered in the submission form. */ - clearSubmissionPluginTmpData(assign: any, submission: any, inputData: any): void { + clearSubmissionPluginTmpData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, inputData: any): void { submission.plugins.forEach((plugin) => { this.submissionDelegate.clearTmpData(assign, submission, plugin, inputData); }); @@ -95,7 +98,7 @@ export class AddonModAssignHelperProvider { * @param previousSubmission Submission to copy. * @return Promise resolved when done. */ - copyPreviousAttempt(assign: any, previousSubmission: any): Promise { + copyPreviousAttempt(assign: AddonModAssignAssign, previousSubmission: AddonModAssignSubmission): Promise { const pluginData = {}, promises = []; @@ -112,6 +115,36 @@ export class AddonModAssignHelperProvider { }); } + /** + * Create an empty feedback object. + * + * @return Feedback. + */ + createEmptyFeedback(): AddonModAssignSubmissionFeedback { + return { + grade: undefined, + gradefordisplay: undefined, + gradeddate: undefined + }; + } + + /** + * Create an empty submission object. + * + * @return Submission. + */ + createEmptySubmission(): AddonModAssignSubmissionFormatted { + return { + id: undefined, + userid: undefined, + attemptnumber: undefined, + timecreated: undefined, + timemodified: undefined, + status: undefined, + groupid: undefined + }; + } + /** * Delete stored submission files for a plugin. See storeSubmissionFiles. * @@ -136,7 +169,9 @@ export class AddonModAssignHelperProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - discardFeedbackPluginData(assignId: number, userId: number, feedback: any, siteId?: string): Promise { + discardFeedbackPluginData(assignId: number, userId: number, feedback: AddonModAssignSubmissionFeedback, + siteId?: string): Promise { + const promises = []; feedback.plugins.forEach((plugin) => { @@ -155,7 +190,9 @@ export class AddonModAssignHelperProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the list of participants and summary of submissions. */ - getParticipants(assign: any, groupId?: number, ignoreCache?: boolean, siteId?: string): Promise { + getParticipants(assign: AddonModAssignAssign, groupId?: number, ignoreCache?: boolean, siteId?: string) + : Promise { + groupId = groupId || 0; siteId = siteId || this.sitesProvider.getCurrentSiteId(); @@ -167,7 +204,7 @@ export class AddonModAssignHelperProvider { // If no participants returned and all groups specified, get participants by groups. return this.groupsProvider.getActivityGroupInfo(assign.cmid, false, undefined, siteId).then((info) => { const promises = [], - participants = {}; + participants: {[id: number]: AddonModAssignParticipant} = {}; info.groups.forEach((userGroup) => { promises.push(this.assignProvider.listParticipants(assign.id, userGroup.id, ignoreCache, siteId) @@ -194,8 +231,8 @@ export class AddonModAssignHelperProvider { * @param type Name of the subplugin. * @return Object containing all configurations of the subplugin selected. */ - getPluginConfig(assign: any, subtype: string, type: string): any { - const configs = {}; + getPluginConfig(assign: AddonModAssignAssign, subtype: string, type: string): {[name: string]: string} { + const configs: {[name: string]: string} = {}; assign.configs.forEach((config) => { if (config.subtype == subtype && config.plugin == type) { @@ -213,7 +250,7 @@ export class AddonModAssignHelperProvider { * @param subtype Subtype name (assignsubmission or assignfeedback) * @return List of enabled plugins for the assign. */ - getPluginsEnabled(assign: any, subtype: string): any[] { + getPluginsEnabled(assign: AddonModAssignAssign, subtype: string): any[] { const enabled = []; assign.configs.forEach((config) => { @@ -250,7 +287,7 @@ export class AddonModAssignHelperProvider { * @param previousSubmission Submission to copy. * @return Promise resolved with the size. */ - getSubmissionSizeForCopy(assign: any, previousSubmission: any): Promise { + getSubmissionSizeForCopy(assign: AddonModAssignAssign, previousSubmission: AddonModAssignSubmission): Promise { const promises = []; let totalSize = 0; @@ -273,7 +310,8 @@ export class AddonModAssignHelperProvider { * @param inputData Data entered in the submission form. * @return Promise resolved with the size. */ - getSubmissionSizeForEdit(assign: any, submission: any, inputData: any): Promise { + getSubmissionSizeForEdit(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, inputData: any): Promise { + const promises = []; let totalSize = 0; @@ -298,14 +336,14 @@ export class AddonModAssignHelperProvider { * @param siteId Site id (empty for current site). * @return Promise always resolved. Resolve param is the formatted submissions. */ - getSubmissionsUserData(assign: any, submissions: any[], groupId?: number, ignoreCache?: boolean, siteId?: string): - Promise { - return this.getParticipants(assign, groupId).then((participants) => { + getSubmissionsUserData(assign: AddonModAssignAssign, submissions: AddonModAssignSubmissionFormatted[], groupId?: number, + ignoreCache?: boolean, siteId?: string): Promise { + + return this.getParticipants(assign, groupId).then((parts) => { const blind = assign.blindmarking && !assign.revealidentities; const promises = []; - const result = []; - - participants = this.utils.arrayToObject(participants, 'id'); + const result: AddonModAssignSubmissionFormatted[] = []; + const participants: {[id: number]: AddonModAssignParticipant} = this.utils.arrayToObject(parts, 'id'); submissions.forEach((submission) => { submission.submitid = submission.userid > 0 ? submission.userid : submission.blindid; @@ -356,10 +394,10 @@ export class AddonModAssignHelperProvider { return Promise.all(promises).then(() => { // Create a submission for each participant left in the list (the participants already treated were removed). - this.utils.objectToArray(participants).forEach((participant) => { - const submission: any = { - submitid: participant.id - }; + this.utils.objectToArray(participants).forEach((participant: AddonModAssignParticipant) => { + const submission = this.createEmptySubmission(); + + submission.submitid = participant.id; if (!blind) { submission.userid = participant.id; @@ -390,17 +428,20 @@ export class AddonModAssignHelperProvider { * Check if the feedback data has changed for a certain submission and assign. * * @param assign Assignment. - * @param userId User Id. + * @param submission The submission. * @param feedback Feedback data. + * @param userId The user ID. * @return Promise resolved with true if data has changed, resolved with false otherwise. */ - hasFeedbackDataChanged(assign: any, userId: number, feedback: any): Promise { + hasFeedbackDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + feedback: AddonModAssignSubmissionFeedback, userId: number): Promise { + const promises = []; let hasChanged = false; feedback.plugins.forEach((plugin) => { promises.push(this.prepareFeedbackPluginData(assign.id, userId, feedback).then((inputData) => { - return this.feedbackDelegate.hasPluginDataChanged(assign, userId, plugin, inputData, userId).then((changed) => { + return this.feedbackDelegate.hasPluginDataChanged(assign, submission, plugin, inputData, userId).then((changed) => { if (changed) { hasChanged = true; } @@ -423,7 +464,9 @@ export class AddonModAssignHelperProvider { * @param inputData Data entered in the submission form. * @return Promise resolved with true if data has changed, resolved with false otherwise. */ - hasSubmissionDataChanged(assign: any, submission: any, inputData: any): Promise { + hasSubmissionDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, inputData: any) + : Promise { + const promises = []; let hasChanged = false; @@ -451,7 +494,9 @@ export class AddonModAssignHelperProvider { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with plugin data to send to server. */ - prepareFeedbackPluginData(assignId: number, userId: number, feedback: any, siteId?: string): Promise { + prepareFeedbackPluginData(assignId: number, userId: number, feedback: AddonModAssignSubmissionFeedback, siteId?: string) + : Promise { + const pluginData = {}, promises = []; @@ -473,7 +518,9 @@ export class AddonModAssignHelperProvider { * @param offline True to prepare the data for an offline submission, false otherwise. * @return Promise resolved with plugin data to send to server. */ - prepareSubmissionPluginData(assign: any, submission: any, inputData: any, offline?: boolean): Promise { + prepareSubmissionPluginData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, inputData: any, + offline?: boolean): Promise { + const pluginData = {}, promises = []; @@ -553,3 +600,16 @@ export class AddonModAssignHelperProvider { } } } + +/** + * Assign submission with some calculated data. + */ +export type AddonModAssignSubmissionFormatted = AddonModAssignSubmission & { + blindid?: number; // Calculated in the app. Blindid of the user that did the submission. + submitid?: number; // Calculated in the app. Userid or blindid of the user that did the submission. + userfullname?: string; // Calculated in the app. Full name of the user that did the submission. + userprofileimageurl?: string; // Calculated in the app. Avatar of the user that did the submission. + manyGroups?: boolean; // Calculated in the app. Whether the user belongs to more than 1 group. + noGroups?: boolean; // Calculated in the app. Whether the user doesn't belong to any group. + groupname?: string; // Calculated in the app. Name of the group the submission belongs to. +}; diff --git a/src/addon/mod/assign/providers/prefetch-handler.ts b/src/addon/mod/assign/providers/prefetch-handler.ts index 284d558ab..228e8e5ad 100644 --- a/src/addon/mod/assign/providers/prefetch-handler.ts +++ b/src/addon/mod/assign/providers/prefetch-handler.ts @@ -26,8 +26,8 @@ import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseHelperProvider } from '@core/course/providers/helper'; import { CoreGradesHelperProvider } from '@core/grades/providers/helper'; import { CoreUserProvider } from '@core/user/providers/user'; -import { AddonModAssignProvider } from './assign'; -import { AddonModAssignHelperProvider } from './helper'; +import { AddonModAssignProvider, AddonModAssignGetSubmissionStatusResult, AddonModAssignSubmission } from './assign'; +import { AddonModAssignHelperProvider, AddonModAssignSubmissionFormatted } from './helper'; import { AddonModAssignSyncProvider } from './assign-sync'; import { AddonModAssignFeedbackDelegate } from './feedback-delegate'; import { AddonModAssignSubmissionDelegate } from './submission-delegate'; @@ -106,7 +106,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan if (data.canviewsubmissions) { // Teacher, get all submissions. return this.assignHelper.getSubmissionsUserData(assign, data.submissions, 0, false, siteId) - .then((submissions) => { + .then((submissions: AddonModAssignSubmissionFormatted[]) => { const promises = []; @@ -161,9 +161,10 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan return this.assignProvider.getSubmissionStatusWithRetry(assign, submitId, undefined, blindMarking, true, false, siteId) .then((response) => { const promises = []; + let userSubmission: AddonModAssignSubmission; if (response.lastattempt) { - const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(assign, response.lastattempt); + userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(assign, response.lastattempt); if (userSubmission && userSubmission.plugins) { // Add submission plugin files. userSubmission.plugins.forEach((plugin) => { @@ -175,7 +176,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan if (response.feedback && response.feedback.plugins) { // Add feedback plugin files. response.feedback.plugins.forEach((plugin) => { - promises.push(this.feedbackDelegate.getPluginFiles(assign, response, plugin, siteId)); + promises.push(this.feedbackDelegate.getPluginFiles(assign, userSubmission, plugin, siteId)); }); } @@ -303,7 +304,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan groupInfo.groups.forEach((group) => { groupProms.push(this.assignHelper.getSubmissionsUserData(assign, data.submissions, group.id, true, siteId) - .then((submissions) => { + .then((submissions: AddonModAssignSubmissionFormatted[]) => { const subPromises = []; @@ -327,7 +328,8 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan } // Prefetch the submission of the current user even if it does not exist, this will be create it. - if (!data.submissions || !data.submissions.find((subm) => subm.submitid == userId)) { + if (!data.submissions || + !data.submissions.find((subm: AddonModAssignSubmissionFormatted) => subm.submitid == userId)) { subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, userId, group.id, false, true, true, siteId).then((subm) => { return this.prefetchSubmission(assign, courseId, moduleId, subm, userId, siteId); @@ -385,15 +387,16 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan * @param siteId Site ID. If not defined, current site. * @return Promise resolved when prefetched, rejected otherwise. */ - protected prefetchSubmission(assign: any, courseId: number, moduleId: number, submission: any, userId?: number, - siteId?: string): Promise { + protected prefetchSubmission(assign: any, courseId: number, moduleId: number, + submission: AddonModAssignGetSubmissionStatusResult, userId?: number, siteId?: string): Promise { const promises = [], blindMarking = assign.blindmarking && !assign.revealidentities; - let userIds = []; + let userIds = [], + userSubmission: AddonModAssignSubmission; if (submission.lastattempt) { - const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(assign, submission.lastattempt); + userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(assign, submission.lastattempt); // Get IDs of the members who need to submit. if (!blindMarking && submission.lastattempt.submissiongroupmemberswhoneedtosubmit) { @@ -440,10 +443,10 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan if (submission.feedback.plugins) { submission.feedback.plugins.forEach((plugin) => { // Prefetch the plugin WS data. - promises.push(this.feedbackDelegate.prefetch(assign, submission, plugin, siteId)); + promises.push(this.feedbackDelegate.prefetch(assign, userSubmission, plugin, siteId)); // Prefetch the plugin files. - promises.push(this.feedbackDelegate.getPluginFiles(assign, submission, plugin, siteId).then((files) => { + promises.push(this.feedbackDelegate.getPluginFiles(assign, userSubmission, plugin, siteId).then((files) => { return this.filepoolProvider.addFilesToQueue(siteId, files, this.component, module.id); }).catch(() => { // Ignore errors. diff --git a/src/addon/mod/assign/providers/submission-delegate.ts b/src/addon/mod/assign/providers/submission-delegate.ts index 70c8e9752..7b65d55ce 100644 --- a/src/addon/mod/assign/providers/submission-delegate.ts +++ b/src/addon/mod/assign/providers/submission-delegate.ts @@ -18,6 +18,7 @@ import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { AddonModAssignDefaultSubmissionHandler } from './default-submission-handler'; +import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin } from './assign'; /** * Interface that all submission handlers must implement. @@ -39,7 +40,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param plugin The plugin object. * @return Boolean or promise resolved with boolean: whether it can be edited in offline. */ - canEditOffline?(assign: any, submission: any, plugin: any): boolean | Promise; + canEditOffline?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin): boolean | Promise; /** * Should clear temporary data for a cancelled submission. @@ -49,7 +51,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param plugin The plugin object. * @param inputData Data entered by the user for the submission. */ - clearTmpData?(assign: any, submission: any, plugin: any, inputData: any): void; + clearTmpData?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): void; /** * This function will be called when the user wants to create a new submission based on the previous one. @@ -62,7 +65,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - copySubmissionData?(assign: any, plugin: any, pluginData: any, userId?: number, siteId?: string): void | Promise; + copySubmissionData?(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin, pluginData: any, + userId?: number, siteId?: string): void | Promise; /** * Delete any stored data for the plugin and submission. @@ -74,7 +78,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - deleteOfflineData?(assign: any, submission: any, plugin: any, offlineData: any, siteId?: string): void | Promise; + deleteOfflineData?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, siteId?: string): void | Promise; /** * Return the Component to use to display the plugin data, either in read or in edit mode. @@ -85,7 +90,7 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param edit Whether the user is editing. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent?(injector: Injector, plugin: any, edit?: boolean): any | Promise; + getComponent?(injector: Injector, plugin: AddonModAssignPlugin, edit?: boolean): any | Promise; /** * Get files used by this plugin. @@ -97,7 +102,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles?(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise; + getPluginFiles?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise; /** * Get a readable name to use for the plugin. @@ -105,7 +111,7 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param plugin The plugin object. * @return The plugin name. */ - getPluginName?(plugin: any): string; + getPluginName?(plugin: AddonModAssignPlugin): string; /** * Get the size of data (in bytes) this plugin will send to copy a previous submission. @@ -114,7 +120,7 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param plugin The plugin object. * @return The size (or promise resolved with size). */ - getSizeForCopy?(assign: any, plugin: any): number | Promise; + getSizeForCopy?(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin): number | Promise; /** * Get the size of data (in bytes) this plugin will send to add or edit a submission. @@ -125,7 +131,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param inputData Data entered by the user for the submission. * @return The size (or promise resolved with size). */ - getSizeForEdit?(assign: any, submission: any, plugin: any, inputData: any): number | Promise; + getSizeForEdit?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): number | Promise; /** * Check if the submission data has changed for this plugin. @@ -136,7 +143,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param inputData Data entered by the user for the submission. * @return Boolean (or promise resolved with boolean): whether the data has changed. */ - hasDataChanged?(assign: any, submission: any, plugin: any, inputData: any): boolean | Promise; + hasDataChanged?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): boolean | Promise; /** * Whether or not the handler is enabled for edit on a site level. @@ -155,7 +163,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - prefetch?(assign: any, submission: any, plugin: any, siteId?: string): Promise; + prefetch?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): Promise; /** * Prepare and add to pluginData the data to send to the server based on the input data. @@ -170,8 +179,9 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSubmissionData?(assign: any, submission: any, plugin: any, inputData: any, pluginData: any, offline?: boolean, - userId?: number, siteId?: string): void | Promise; + prepareSubmissionData?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, pluginData: any, offline?: boolean, + userId?: number, siteId?: string): void | Promise; /** * Prepare and add to pluginData the data to send to the server based on the offline data stored. @@ -185,8 +195,8 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler { * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSyncData?(assign: any, submission: any, plugin: any, offlineData: any, pluginData: any, siteId?: string) - : void | Promise; + prepareSyncData?(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, pluginData: any, siteId?: string): void | Promise; } /** @@ -210,7 +220,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param plugin The plugin object. * @return Promise resolved with boolean: whether it can be edited in offline. */ - canPluginEditOffline(assign: any, submission: any, plugin: any): Promise { + canPluginEditOffline(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'canEditOffline', [assign, submission, plugin])); } @@ -222,7 +233,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param plugin The plugin object. * @param inputData Data entered by the user for the submission. */ - clearTmpData(assign: any, submission: any, plugin: any, inputData: any): void { + clearTmpData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): void { return this.executeFunctionOnEnabled(plugin.type, 'clearTmpData', [assign, submission, plugin, inputData]); } @@ -236,7 +248,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when the data has been copied. */ - copyPluginSubmissionData(assign: any, plugin: any, pluginData: any, userId?: number, siteId?: string): void | Promise { + copyPluginSubmissionData(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin, pluginData: any, + userId?: number, siteId?: string): void | Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'copySubmissionData', [assign, plugin, pluginData, userId, siteId])); } @@ -251,7 +264,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - deletePluginOfflineData(assign: any, submission: any, plugin: any, offlineData: any, siteId?: string): Promise { + deletePluginOfflineData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'deleteOfflineData', [assign, submission, plugin, offlineData, siteId])); } @@ -264,7 +278,7 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param edit Whether the user is editing. * @return Promise resolved with the component to use, undefined if not found. */ - getComponentForPlugin(injector: Injector, plugin: any, edit?: boolean): Promise { + getComponentForPlugin(injector: Injector, plugin: AddonModAssignPlugin, edit?: boolean): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'getComponent', [injector, plugin, edit])); } @@ -278,7 +292,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the files. */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'getPluginFiles', [assign, submission, plugin, siteId])); } @@ -288,7 +303,7 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param plugin Plugin to get the name for. * @return Human readable name. */ - getPluginName(plugin: any): string { + getPluginName(plugin: AddonModAssignPlugin): string { return this.executeFunctionOnEnabled(plugin.type, 'getPluginName', [plugin]); } @@ -299,7 +314,7 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param plugin The plugin object. * @return Promise resolved with size. */ - getPluginSizeForCopy(assign: any, plugin: any): Promise { + getPluginSizeForCopy(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'getSizeForCopy', [assign, plugin])); } @@ -312,7 +327,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param inputData Data entered by the user for the submission. * @return Promise resolved with size. */ - getPluginSizeForEdit(assign: any, submission: any, plugin: any, inputData: any): Promise { + getPluginSizeForEdit(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'getSizeForEdit', [assign, submission, plugin, inputData])); } @@ -326,7 +342,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param inputData Data entered by the user for the submission. * @return Promise resolved with true if data has changed, resolved with false otherwise. */ - hasPluginDataChanged(assign: any, submission: any, plugin: any, inputData: any): Promise { + hasPluginDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'hasDataChanged', [assign, submission, plugin, inputData])); } @@ -360,7 +377,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - prefetch(assign: any, submission: any, plugin: any, siteId?: string): Promise { + prefetch(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, plugin: AddonModAssignPlugin, + siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'prefetch', [assign, submission, plugin, siteId])); } @@ -377,8 +395,9 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when data has been gathered. */ - preparePluginSubmissionData(assign: any, submission: any, plugin: any, inputData: any, pluginData: any, offline?: boolean, - userId?: number, siteId?: string): Promise { + preparePluginSubmissionData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, pluginData: any, offline?: boolean, userId?: number, + siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'prepareSubmissionData', [assign, submission, plugin, inputData, pluginData, offline, userId, siteId])); @@ -395,8 +414,8 @@ export class AddonModAssignSubmissionDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved when data has been gathered. */ - preparePluginSyncData(assign: any, submission: any, plugin: any, offlineData: any, pluginData: any, siteId?: string) - : Promise { + preparePluginSyncData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, pluginData: any, siteId?: string): Promise { return Promise.resolve(this.executeFunctionOnEnabled(plugin.type, 'prepareSyncData', [assign, submission, plugin, offlineData, pluginData, siteId])); diff --git a/src/addon/mod/assign/submission/comments/providers/handler.ts b/src/addon/mod/assign/submission/comments/providers/handler.ts index 54f450df5..a608d2132 100644 --- a/src/addon/mod/assign/submission/comments/providers/handler.ts +++ b/src/addon/mod/assign/submission/comments/providers/handler.ts @@ -17,6 +17,9 @@ import { Injectable, Injector } from '@angular/core'; import { CoreCommentsProvider } from '@core/comments/providers/comments'; import { AddonModAssignSubmissionHandler } from '../../../providers/submission-delegate'; import { AddonModAssignSubmissionCommentsComponent } from '../component/comments'; +import { + AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../../providers/assign'; /** * Handler for comments submission plugin. @@ -38,7 +41,8 @@ export class AddonModAssignSubmissionCommentsHandler implements AddonModAssignSu * @param plugin The plugin object. * @return Boolean or promise resolved with boolean: whether it can be edited in offline. */ - canEditOffline(assign: any, submission: any, plugin: any): boolean | Promise { + canEditOffline(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin): boolean | Promise { // This plugin is read only, but return true to prevent blocking the edition. return true; } @@ -52,7 +56,7 @@ export class AddonModAssignSubmissionCommentsHandler implements AddonModAssignSu * @param edit Whether the user is editing. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any, edit?: boolean): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin, edit?: boolean): any | Promise { return edit ? undefined : AddonModAssignSubmissionCommentsComponent; } @@ -84,7 +88,9 @@ export class AddonModAssignSubmissionCommentsHandler implements AddonModAssignSu * @param siteId Site ID. If not defined, current site. * @return Promise resolved when done. */ - prefetch(assign: any, submission: any, plugin: any, siteId?: string): Promise { + prefetch(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): Promise { + return this.commentsProvider.getComments('module', assign.cmid, 'assignsubmission_comments', submission.id, 'submission_comments', 0, siteId).catch(() => { // Fail silently (Moodle < 3.1.1, 3.2) diff --git a/src/addon/mod/assign/submission/file/providers/handler.ts b/src/addon/mod/assign/submission/file/providers/handler.ts index 57a4a70bf..7fe7388dc 100644 --- a/src/addon/mod/assign/submission/file/providers/handler.ts +++ b/src/addon/mod/assign/submission/file/providers/handler.ts @@ -21,7 +21,9 @@ import { CoreSitesProvider } from '@providers/sites'; import { CoreWSProvider } from '@providers/ws'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader'; -import { AddonModAssignProvider } from '../../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../../providers/assign'; import { AddonModAssignOfflineProvider } from '../../../providers/assign-offline'; import { AddonModAssignHelperProvider } from '../../../providers/helper'; import { AddonModAssignSubmissionHandler } from '../../../providers/submission-delegate'; @@ -53,7 +55,8 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param plugin The plugin object. * @return Boolean or promise resolved with boolean: whether it can be edited in offline. */ - canEditOffline(assign: any, submission: any, plugin: any): boolean | Promise { + canEditOffline(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin): boolean | Promise { // This plugin doesn't use Moodle filters, it can be edited in offline. return true; } @@ -66,7 +69,8 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param plugin The plugin object. * @param inputData Data entered by the user for the submission. */ - clearTmpData(assign: any, submission: any, plugin: any, inputData: any): void { + clearTmpData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): void { const files = this.fileSessionProvider.getFiles(AddonModAssignProvider.COMPONENT, assign.id); // Clear the files in session for this assign. @@ -87,7 +91,9 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - copySubmissionData(assign: any, plugin: any, pluginData: any, userId?: number, siteId?: string): void | Promise { + copySubmissionData(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin, pluginData: any, + userId?: number, siteId?: string): void | Promise { + // We need to re-upload all the existing files. const files = this.assignProvider.getSubmissionPluginAttachments(plugin); @@ -105,7 +111,7 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param edit Whether the user is editing. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any, edit?: boolean): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin, edit?: boolean): any | Promise { return AddonModAssignSubmissionFileComponent; } @@ -119,7 +125,9 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - deleteOfflineData(assign: any, submission: any, plugin: any, offlineData: any, siteId?: string): void | Promise { + deleteOfflineData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, siteId?: string): void | Promise { + return this.assignHelper.deleteStoredSubmissionFiles(assign.id, AddonModAssignSubmissionFileHandler.FOLDER_NAME, submission.userid, siteId).catch(() => { // Ignore errors, maybe the folder doesn't exist. @@ -136,7 +144,8 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise { return this.assignProvider.getSubmissionPluginAttachments(plugin); } @@ -147,7 +156,7 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param plugin The plugin object. * @return The size (or promise resolved with size). */ - getSizeForCopy(assign: any, plugin: any): number | Promise { + getSizeForCopy(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin): number | Promise { const files = this.assignProvider.getSubmissionPluginAttachments(plugin), promises = []; let totalSize = 0; @@ -177,7 +186,8 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param inputData Data entered by the user for the submission. * @return The size (or promise resolved with size). */ - getSizeForEdit(assign: any, submission: any, plugin: any, inputData: any): number | Promise { + getSizeForEdit(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): number | Promise { const siteId = this.sitesProvider.getCurrentSiteId(); // Check if there's any change. @@ -232,7 +242,9 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param inputData Data entered by the user for the submission. * @return Boolean (or promise resolved with boolean): whether the data has changed. */ - hasDataChanged(assign: any, submission: any, plugin: any, inputData: any): boolean | Promise { + hasDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): boolean | Promise { + // Check if there's any offline data. return this.assignOfflineProvider.getSubmission(assign.id, submission.userid).catch(() => { // No offline data found. @@ -299,7 +311,8 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSubmissionData(assign: any, submission: any, plugin: any, inputData: any, pluginData: any, offline?: boolean, + prepareSubmissionData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, pluginData: any, offline?: boolean, userId?: number, siteId?: string): void | Promise { if (this.hasDataChanged(assign, submission, plugin, inputData)) { @@ -330,8 +343,8 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSyncData(assign: any, submission: any, plugin: any, offlineData: any, pluginData: any, siteId?: string) - : void | Promise { + prepareSyncData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, pluginData: any, siteId?: string): void | Promise { const filesData = offlineData && offlineData.plugindata && offlineData.plugindata.files_filemanager; if (filesData) { diff --git a/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html b/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html index a231c0cfa..5d2565e06 100644 --- a/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html +++ b/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html @@ -10,7 +10,7 @@
{{ plugin.name }} - +

{{ 'addon.mod_assign.wordlimit' | translate }}

{{ 'core.numwords' | translate: {'$a': words + ' / ' + configs.wordlimit} }}

diff --git a/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts b/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts index 25b0cd5e6..b5c6d4045 100644 --- a/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts +++ b/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts @@ -34,6 +34,7 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS component = AddonModAssignProvider.COMPONENT; text: string; loaded: boolean; + wordLimitEnabled: boolean; protected wordCountTimeout: any; protected element: HTMLElement; @@ -61,9 +62,7 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS // No offline data found, return online text. return this.assignProvider.getSubmissionPluginText(this.plugin); }).then((text) => { - // We receive them as strings, convert to int. - this.configs.wordlimit = parseInt(this.configs.wordlimit, 10); - this.configs.wordlimitenabled = parseInt(this.configs.wordlimitenabled, 10); + this.wordLimitEnabled = !!parseInt(this.configs.wordlimitenabled, 10); // Set the text. this.text = text; @@ -85,7 +84,7 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS } // Calculate initial words. - if (this.configs.wordlimitenabled) { + if (this.wordLimitEnabled) { this.words = this.textUtils.countWords(text); } }).finally(() => { @@ -100,7 +99,7 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS */ onChange(text: string): void { // Count words if needed. - if (this.configs.wordlimitenabled) { + if (this.wordLimitEnabled) { // Cancel previous wait. clearTimeout(this.wordCountTimeout); diff --git a/src/addon/mod/assign/submission/onlinetext/providers/handler.ts b/src/addon/mod/assign/submission/onlinetext/providers/handler.ts index dd4b847a4..69a84b85e 100644 --- a/src/addon/mod/assign/submission/onlinetext/providers/handler.ts +++ b/src/addon/mod/assign/submission/onlinetext/providers/handler.ts @@ -18,7 +18,9 @@ import { TranslateService } from '@ngx-translate/core'; import { CoreSitesProvider } from '@providers/sites'; import { CoreWSProvider } from '@providers/ws'; import { CoreTextUtilsProvider } from '@providers/utils/text'; -import { AddonModAssignProvider } from '../../../providers/assign'; +import { + AddonModAssignProvider, AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin +} from '../../../providers/assign'; import { AddonModAssignOfflineProvider } from '../../../providers/assign-offline'; import { AddonModAssignHelperProvider } from '../../../providers/helper'; import { AddonModAssignSubmissionHandler } from '../../../providers/submission-delegate'; @@ -46,7 +48,8 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param plugin The plugin object. * @return Boolean or promise resolved with boolean: whether it can be edited in offline. */ - canEditOffline(assign: any, submission: any, plugin: any): boolean | Promise { + canEditOffline(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin): boolean | Promise { // This plugin uses Moodle filters, it cannot be edited in offline. return false; } @@ -62,7 +65,9 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - copySubmissionData(assign: any, plugin: any, pluginData: any, userId?: number, siteId?: string): void | Promise { + copySubmissionData(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin, pluginData: any, + userId?: number, siteId?: string): void | Promise { + const text = this.assignProvider.getSubmissionPluginText(plugin, true), files = this.assignProvider.getSubmissionPluginAttachments(plugin); let promise; @@ -93,7 +98,7 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param edit Whether the user is editing. * @return The component (or promise resolved with component) to use, undefined if not found. */ - getComponent(injector: Injector, plugin: any, edit?: boolean): any | Promise { + getComponent(injector: Injector, plugin: AddonModAssignPlugin, edit?: boolean): any | Promise { return AddonModAssignSubmissionOnlineTextComponent; } @@ -107,7 +112,8 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param siteId Site ID. If not defined, current site. * @return The files (or promise resolved with the files). */ - getPluginFiles(assign: any, submission: any, plugin: any, siteId?: string): any[] | Promise { + getPluginFiles(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, siteId?: string): any[] | Promise { return this.assignProvider.getSubmissionPluginAttachments(plugin); } @@ -118,7 +124,7 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param plugin The plugin object. * @return The size (or promise resolved with size). */ - getSizeForCopy(assign: any, plugin: any): number | Promise { + getSizeForCopy(assign: AddonModAssignAssign, plugin: AddonModAssignPlugin): number | Promise { const text = this.assignProvider.getSubmissionPluginText(plugin, true), files = this.assignProvider.getSubmissionPluginAttachments(plugin), promises = []; @@ -153,7 +159,8 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param inputData Data entered by the user for the submission. * @return The size (or promise resolved with size). */ - getSizeForEdit(assign: any, submission: any, plugin: any, inputData: any): number | Promise { + getSizeForEdit(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): number | Promise { const text = this.assignProvider.getSubmissionPluginText(plugin, true); return text.length; @@ -182,7 +189,9 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param inputData Data entered by the user for the submission. * @return Boolean (or promise resolved with boolean): whether the data has changed. */ - hasDataChanged(assign: any, submission: any, plugin: any, inputData: any): boolean | Promise { + hasDataChanged(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any): boolean | Promise { + // Get the original text from plugin or offline. return this.assignOfflineProvider.getSubmission(assign.id, submission.userid).catch(() => { // No offline data found. @@ -234,7 +243,8 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSubmissionData(assign: any, submission: any, plugin: any, inputData: any, pluginData: any, offline?: boolean, + prepareSubmissionData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, inputData: any, pluginData: any, offline?: boolean, userId?: number, siteId?: string): void | Promise { let text = this.getTextToSubmit(plugin, inputData); @@ -274,8 +284,8 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign * @param siteId Site ID. If not defined, current site. * @return If the function is async, it should return a Promise resolved when done. */ - prepareSyncData(assign: any, submission: any, plugin: any, offlineData: any, pluginData: any, siteId?: string) - : void | Promise { + prepareSyncData(assign: AddonModAssignAssign, submission: AddonModAssignSubmission, + plugin: AddonModAssignPlugin, offlineData: any, pluginData: any, siteId?: string): void | Promise { const textData = offlineData && offlineData.plugindata && offlineData.plugindata.onlinetext_editor; if (textData) {