"use strict";
/**
* Functions for interacting with assignments within courses
* @namespace api.course.assignment
*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// Import shared classes
var EndpointCategory_1 = __importDefault(require("../../shared/EndpointCategory"));
var caccl_error_1 = __importDefault(require("caccl-error"));
var ErrorCode_1 = __importDefault(require("../../shared/types/ErrorCode"));
// Import shared helpers
var utils_1 = __importDefault(require("../../shared/helpers/utils"));
var waitForCompletion_1 = __importDefault(require("../../shared/helpers/waitForCompletion"));
var parallelLimit_1 = __importDefault(require("../../shared/helpers/parallelLimit"));
// Import shared constants
var API_PREFIX_1 = __importDefault(require("../../shared/constants/API_PREFIX"));
// Endpoint category
var ECatAssignment = /** @class */ (function (_super) {
__extends(ECatAssignment, _super);
function ECatAssignment() {
return _super !== null && _super.apply(this, arguments) || this;
}
/*------------------------------------------------------------------------*/
/* Table of Contents: */
/* - Assignments */
/* - Grading */
/* - Overrides */
/* - Submissions */
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/* Assignment Endpoints */
/*------------------------------------------------------------------------*/
/**
* Lists the assignments in a course
* @author Gabe Abrams
* @method list
* @memberof api.course.assignment
* @instance
* @async
* @param {object} [opts] object containing all arguments
* @param {number} [opts.courseId=default course id] Canvas course Id to
* query
* @param {boolean} [opts.ignoreOverridesForDates] if true, assignment
* dates are taken from the default dates instead of from the ones in
* overrides
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignment[]>} list of Canvas Assignments {@link https://canvas.instructure.com/doc/api/assignments.html#Assignment}
*/
ECatAssignment.prototype.list = function (opts, config) {
var _a;
if (opts === void 0) { opts = {}; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'get the list of assignments in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments"),
method: 'GET',
params: {
override_assignment_dates: !opts.ignoreOverridesForDates,
},
})];
});
});
};
/**
* Get info on a specific assignment in a course
* @author Gabe Abrams
* @method get
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment Id
* @param {number} [opts.courseId=default course id] Canvas course Id to query
* @param {boolean} [opts.ignoreOverridesForDates] if true, assignment
* dates are taken from the default dates instead of from the ones in
* overrides
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignment>} Canvas Assignment {@link https://canvas.instructure.com/doc/api/assignments.html#Assignment}
*/
ECatAssignment.prototype.get = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'get info on a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId),
method: 'GET',
params: {
override_assignment_dates: !opts.ignoreOverridesForDates,
},
})];
});
});
};
/**
* Updates a Canvas assignment
* @author Gabe Abrams
* @method update
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts - object containing all arguments
* @param {number} opts.assignmentId Canvas assignment Id to update
* @param {number} [opts.courseId=default course id] Canvas course Id to query
* @param {string} [opts.name=current value] The name of the assignment
* @param {number} [opts.pointsPossible=current value] Points possible
* @param {date} [opts.dueAt=current value] Due at datetime
* @param {date} [opts.lockAt=current value] Due at datetime
* @param {date} [opts.unlockAt=current value] Due at datetime
* @param {string} [opts.description=current value] html description of
* the assignment
* @param {string[]} [opts.submissionTypes=current value] Submission type(s)
* @param {string} [opts.allowedExtensions=current value] List of allowed
* file extensions (exclude period). Online upload must be enabled
* @param {string} [opts.gradingType=current value] Grading type
* @param {number} [opts.position=current value] Position in assignment
* list
* @param {boolean} [opts.published=current value] If true, publish page
* upon creation. Must be a boolean
* @param {boolean} [opts.muted=current value] If true, assignment is
* muted. Must be a boolean
* @param {number} [opts.groupSetId=current value] Student group set Id
* @param {number} [opts.assignmentGroupId=current value] Assignment group
* Id
* @param {boolean} [opts.peerReviewsEnabled=current value] If true, users
* asked to submit peer reviews. Must be a boolean
* @param {boolean} [opts.automaticPeerReviewsEnabled=current value] If
* true, Canvas will automatically assign peer reviews. Must be a boolean
* @param {boolean} [opts.omitFromFinalGrade=current value] If true,
* assignment is omitted from the final grade. Must be a boolean
* @param {boolean} [opts.gradeGroupStudentsIndividually=current value] If
* true, students in groups can be given separate grades and when one student
* in a group gets a grade, other students do not get graded. Must be a
* boolean
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignment>} Canvas Assignment {@link https://canvas.instructure.com/doc/api/assignments.html#Assignment}
*/
ECatAssignment.prototype.update = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'update an assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId),
method: 'PUT',
params: {
'assignment[name]': utils_1.default.includeIfTruthy(opts.name),
'assignment[submission_types]': utils_1.default.includeIfTruthy(opts.submissionTypes),
'assignment[grading_type]': utils_1.default.includeIfTruthy(opts.gradingType),
position: utils_1.default.includeIfTruthy(opts.position),
'assignment[peer_reviews]': utils_1.default.includeIfBoolean(opts.peerReviewsEnabled),
'assignment[automatic_peer_reviews]': utils_1.default.includeIfBoolean(opts.automaticPeerReviewsEnabled),
'assignment[grade_group_students_individually]': utils_1.default.includeIfBoolean(opts.gradeGroupStudentsIndividually),
'assignment[description]': utils_1.default.includeIfTruthy(opts.description),
'assignment[allowed_extensions]': utils_1.default.includeIfTruthy(opts.allowedExtensions),
'assignment[group_category_id]': utils_1.default.includeIfTruthy(opts.groupSetId),
'assignment[points_possible]': utils_1.default.includeIfNumber(opts.pointsPossible),
'assignment[due_at]': utils_1.default.includeIfDate(opts.dueAt),
'assignment[lock_at]': utils_1.default.includeIfDate(opts.lockAt),
'assignment[unlock_at]': utils_1.default.includeIfDate(opts.unlockAt),
'assignment[published]': utils_1.default.includeIfBoolean(opts.published),
'assignment[assignment_group_id]': utils_1.default.includeIfNumber(opts.assignmentGroupId),
'assignment[omit_from_final_grade]': utils_1.default.includeIfBoolean(opts.omitFromFinalGrade),
'assignment[muted]': utils_1.default.includeIfBoolean(opts.muted),
},
})];
});
});
};
/**
* Creates a Canvas assignment
* @author Gabe Abrams
* @method create
* @memberof api.course.assignment
* @instance
* @async
* @param {object} [opts] object containing all arguments
* @param {number} [opts.courseId=default course id] Canvas course Id to
* create an assignment in
* @param {string} [opts.name=Unnamed Assignment] The name of the
* assignment
* @param {number} [opts.pointsPossible=null] Points possible
* @param {date} [opts.dueAt=null] Due at datetime
* @param {date} [opts.lockAt=null] Due at datetime
* @param {date} [opts.unlockAt=null] Due at datetime
* @param {string} [opts.description=null] html description of
* the assignment
* @param {string} [opts.submissionTypes=null] Submission type(s)
* @param {string} [opts.allowedExtensions=any] List of allowed file
* extensions (exclude period). Online upload must be enabled
* @param {string} [opts.gradingType=points] Grading type
* @param {number} [opts.position=last] Position in assignment list
* @param {boolean} [opts.published] If true, publish page upon
* creation
* @param {boolean} [opts.muted] If true, assignment is muted
* @param {number} [opts.groupSetId=null] Student group set Id
* @param {number} [opts.assignmentGroupId=top assignment group] Assignment
* group Id
* @param {boolean} [opts.peerReviewsEnabled] If true, users asked to
* submit peer reviews
* @param {boolean} [opts.automaticPeerReviewsEnabled] If true,
* Canvas will automatically assign peer reviews
* @param {boolean} [opts.omitFromFinalGrade] If true, assignment is
* omitted from the final grade
* @param {boolean} [opts.gradeGroupStudentsIndividually] If true,
* students in groups can be given separate grades and when one student in a
* group gets a grade, other students do not get graded
* @param {string} [opts.assignmentAppId=null] If defined, the external
* tool that matches this id will be used for submissions. Also, the
* submission types will be overwritten with ['external_tool'] and the
* student will be redirected via LTI to the assignmentAppURL when they
* launch the assignment
* @param {string} [opts.assignmentAppURL=tool launch url] The launch URL
* of the external tool. If not included and assignmentAppId is defined, we
* will first request info on the external tool to get its launchURL and
* will use that value here. Only relevant if assignmentAppId is defined.
* @param {boolean} [opts.assignmentAppNewTab] Only relevant if
* assignmentAppId is defined. If true, when a student clicks the
* assignment, their LTI session with the external tool will be opened in a
* new tab
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignment>} Canvas Assignment {@link https://canvas.instructure.com/doc/api/assignments.html#Assignment}
*/
ECatAssignment.prototype.create = function (opts, config) {
var _a, _b;
if (opts === void 0) { opts = {}; }
return __awaiter(this, void 0, void 0, function () {
var params, app;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
params = {
'assignment[name]': (opts.name || 'Unnamed Assignment'),
'assignment[grading_type]': (opts.gradingType || 'points'),
position: utils_1.default.includeIfTruthy(opts.position),
'assignment[peer_reviews]': (utils_1.default.isTruthy(opts.peerReviewsEnabled)),
'assignment[automatic_peer_reviews]': utils_1.default.isTruthy(opts.automaticPeerReviewsEnabled),
'assignment[grade_group_students_individually]': utils_1.default.isTruthy(opts.gradeGroupStudentsIndividually),
'assignment[description]': (utils_1.default.includeIfTruthy(opts.description)),
'assignment[allowed_extensions]': (utils_1.default.includeIfTruthy(opts.allowedExtensions)),
'assignment[group_category_id]': (utils_1.default.includeIfTruthy(opts.groupSetId)),
'assignment[points_possible]': (utils_1.default.includeIfNumber(opts.pointsPossible)),
'assignment[due_at]': utils_1.default.includeIfDate(opts.dueAt),
'assignment[lock_at]': utils_1.default.includeIfDate(opts.lockAt),
'assignment[unlock_at]': utils_1.default.includeIfDate(opts.unlockAt),
'assignment[published]': (utils_1.default.isTruthy(opts.published)),
'assignment[assignment_group_id]': (utils_1.default.includeIfNumber(opts.assignmentGroupId)),
'assignment[omit_from_final_grade]': (utils_1.default.isTruthy(opts.omitFromFinalGrade)),
'assignment[muted]': utils_1.default.isTruthy(opts.muted),
};
if (!opts.assignmentAppId) return [3 /*break*/, 4];
// Using an external tool
params['assignment[external_tool_tag_attributes][new_tab]'] = (!!opts.assignmentAppNewTab);
params['assignment[external_tool_tag_attributes][content_type]'] = ('context_external_tool');
params['assignment[external_tool_tag_attributes][content_id]'] = (opts.assignmentAppId);
params['assignment[submission_types]'] = ['external_tool'];
if (!opts.assignmentAppURL) return [3 /*break*/, 1];
// No need to fetch the launchURL
params['assignment[external_tool_tag_attributes][url]'] = (opts.assignmentAppURL);
return [3 /*break*/, 3];
case 1: return [4 /*yield*/, this.api.course.app.get({
courseId: ((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId),
appId: opts.assignmentAppId,
}, config)];
case 2:
app = _c.sent();
params['assignment[external_tool_tag_attributes][url]'] = app.url;
_c.label = 3;
case 3: return [3 /*break*/, 5];
case 4:
params['assignment[submission_types]'] = (opts.submissionTypes || ['none']);
_c.label = 5;
case 5: return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'create a new assignment in a course',
params: params,
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_b = opts.courseId) !== null && _b !== void 0 ? _b : this.defaultCourseId, "/assignments"),
method: 'POST',
})];
}
});
});
};
/**
* Delete an assignment
* @author Gabe Abrams
* @method delete
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment Id
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignment>} Canvas Assignment {@link https://canvas.instructure.com/doc/api/assignments.html#Assignment}
*/
ECatAssignment.prototype.delete = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'delete an assignment from a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId),
method: 'DELETE',
})];
});
});
};
/*------------------------------------------------------------------------*/
/* Grading Endpoints */
/*------------------------------------------------------------------------*/
/**
* List gradeable students for a specific assignment
* @author Gabe Abrams
* @method listGradeableStudents
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment Id to query
* @param {number} [opts.courseId=default course id] Canvas course Id to
* query
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasUser[]>} list of Canvas users {@link https://canvas.instructure.com/doc/api/users.html#User}
*/
ECatAssignment.prototype.listGradeableStudents = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var students;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.visitEndpoint({
config: config,
action: 'get the list of students who are gradeable in a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/gradeable_students"),
method: 'GET',
})];
case 1:
students = _b.sent();
return [2 /*return*/, students.filter(function (s) {
return !s.fake_student;
})];
}
});
});
};
/**
* Adds a comment to a submission
* @author Gabe Abrams
* @method createSubmissionComment
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas course Id
* @param {number} opts.studentId Canvas student Id of the sub to comment
* on
* @param {string} opts.comment The text of the comment
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasSubmission>} Canvas submission {@link https://canvas.instructure.com/doc/api/submissions.html#Submission}
*/
ECatAssignment.prototype.createSubmissionComment = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'create a new comment on a submission',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/submissions/").concat(opts.studentId),
method: 'PUT',
params: {
'comment[text_comment]': opts.comment,
},
})];
});
});
};
/**
* Updates a student's grade and/or comment
* @author Gabe Abrams
* @method updateGrade
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment id
* @param {number} opts.studentId Canvas student id
* @param {number} [opts.courseId=default course id] Canvas course id
* @param {number} [opts.points] the overall points to assign to the
* student
* @param {string} [opts.comment] the grader comment to leave on the
* submission
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasSubmission>} Canvas submission {@link https://canvas.instructure.com/doc/api/submissions.html#Submission}
*/
ECatAssignment.prototype.updateGrade = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'update student grade and/or comments for a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/submissions/").concat(opts.studentId),
method: 'PUT',
params: {
'comment[text_comment]': utils_1.default.includeIfTruthy(opts.comment),
'submission[posted_grade]': utils_1.default.includeIfNumber(opts.points),
},
})];
});
});
};
/**
* Batch updates grades and/or comments. Also supports updating rubric items
* @author Gabe Abrams
* @method updateGrades
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment Id
* @param {Array} opts.gradeItems List of grade items to upload to Canvas:
* [{
* studentId: <student id>,
* points: <optional, points to overwrite with>,
* comment: <optional, comment to append (or overwrite if rubric comment)>,
* rubricId: <optional, rubric item (overall grade/comment if excluded)>
* },...]
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {boolean} [opts.waitForCompletion] If true, promise won't
* resolve until Canvas has finished updating the grades, instead of resolving
* once the grade changes have been queued
* @param {number} [opts.waitForCompletionTimeout=2] The number of minutes
* to wait before timing out the grade update job
* @param {boolean} [opts.dontMergeRubricItemUpdates] When uploading
* grades to a rubric item, we intelligently merge rubric item updates with
* previous rubric assessments. For instance, if the assignment's rubric is:
* { grammar, argument, formatting }
* And the student of interest has the following rubric assessment so far:
* { grammar: 10/10, argument: 8/10, formatting: ungraded }
* When we upload a new gradeItem (9/10 points) to the student's
* formatting rubric item, the result is:
* { grammar: 10/10, argument: 8/10, formatting: 9/10 }
* However, if dontMergeRubricItemUpdates=true, the result is:
* { grammar: ungraded, argument: ungraded, formatting: 9/10 }
* Note: merging is an added feature. By default, the Canvas API does not
* merge rubric assessments.
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasProgress>} Canvas Progress object {@link https://canvas.instructure.com/doc/api/progress.html#Progress}
*/
ECatAssignment.prototype.updateGrades = function (opts, config) {
var _a, _b;
return __awaiter(this, void 0, void 0, function () {
var studentsToMerge, performRubricItemMerge, assignment, realRubricItemIds_1, numRubricItems_1, studentToRubricItemsOverwritten_1, allStudentsWithRubricItems_1, subs, params, overwritingMap_1, progress, finishedProgress;
var _this = this;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
studentsToMerge = [];
performRubricItemMerge = false;
if (!opts.dontMergeRubricItemUpdates) {
performRubricItemMerge = opts.gradeItems.some(function (item) {
return item.rubricId;
});
}
if (!performRubricItemMerge) return [3 /*break*/, 2];
return [4 /*yield*/, this.api.course.assignment.get({
courseId: ((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId),
assignmentId: opts.assignmentId,
}, config)];
case 1:
assignment = _c.sent();
// Make sure the assignment has a rubric
if (!assignment.rubric) {
// This assignment doesn't have a rubric
throw new caccl_error_1.default({
message: 'We could not upload grades because the rubric we were trying to upload to didn\'t exist.',
code: ErrorCode_1.default.NoRubricOnBatchGradeUpload,
});
}
realRubricItemIds_1 = new Set();
numRubricItems_1 = assignment.rubric.length;
assignment.rubric.forEach(function (rubricItem) {
realRubricItemIds_1.add(rubricItem.id);
});
studentToRubricItemsOverwritten_1 = (new Map());
allStudentsWithRubricItems_1 = new Set();
// ^ {studentId => { Set of rubric ids being uploaded }}
opts.gradeItems.forEach(function (gradeItem) {
var rubricId = gradeItem.rubricId, studentId = gradeItem.studentId;
allStudentsWithRubricItems_1.add(studentId);
// Skip if this item isn't a (real) rubric item
if (!rubricId || realRubricItemIds_1.has(rubricId)) {
return;
}
// Only mark this rubric item as being overwritten if both points and
// comments are being overwritten
if (gradeItem.points === undefined
|| gradeItem.points === null
|| !gradeItem.comment) {
// Not completely overwriting
return;
}
// Keep track of rubric items that are found
if (!studentToRubricItemsOverwritten_1.has(studentId)) {
// Initialize student map
studentToRubricItemsOverwritten_1.set(studentId, new Set());
}
studentToRubricItemsOverwritten_1.get(studentId).add(rubricId);
});
// > Find students that need to be merged (has some rubric items but not
// completely overwriting all of them)
allStudentsWithRubricItems_1.forEach(function (studentId) {
var numOverwrittenItems = ((studentToRubricItemsOverwritten_1.get(studentId)
|| { size: 0 }).size);
if (numOverwrittenItems < numRubricItems_1) {
// Need to merge this student
studentsToMerge.push(studentId);
}
});
_c.label = 2;
case 2: return [4 /*yield*/, (0, parallelLimit_1.default)(studentsToMerge.map(function (studentId) {
return function () { return __awaiter(_this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
return [2 /*return*/, this.api.course.assignment.getSubmission({
studentId: studentId,
courseId: ((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId),
assignmentId: opts.assignmentId,
includeRubricAssessment: true,
excludeUser: true, // Save request space
}, config)];
});
}); };
}), 10)];
case 3:
subs = _c.sent();
params = {};
if (subs.length > 0) {
overwritingMap_1 = {};
// ^ {studentId => rubricId => {
// points: true/false, is being overwritten,
// comment: true/false, is being overwritten
// }}
opts.gradeItems.forEach(function (gradeItem) {
if (!gradeItem.rubricId) {
// No need to keep track of non-rubric item updates
// (these are not being merged)
return;
}
var sid = gradeItem.studentId;
var rid = gradeItem.rubricId;
// Initialize map if needed
if (!overwritingMap_1[sid]) {
overwritingMap_1[sid] = {};
}
if (!overwritingMap_1[sid][rid]) {
overwritingMap_1[sid][rid] = { points: false, comment: false };
}
// Save points and comments
if (gradeItem.points !== undefined) {
overwritingMap_1[sid][rid].points = true;
}
if (gradeItem.comment !== undefined) {
overwritingMap_1[sid][rid].comment = true;
}
});
// Perform actual merge
subs.forEach(function (sub) {
if (!sub.rubric_assessment) {
// No need to merge: submission has no rubric content yet
return;
}
var sid = sub.user_id;
// Loop through rubric items and merge
Object.keys(sub.rubric_assessment).forEach(function (rubricId) {
// Get previous values
var oldPoints = sub.rubric_assessment[rubricId].points;
var oldComment = sub.rubric_assessment[rubricId].comments;
// Check if we're overwriting these values
var overwritePoints;
var overwriteComment;
if (overwritingMap_1[sid] && overwritingMap_1[sid][rubricId]) {
overwritePoints = overwritingMap_1[sid][rubricId].points;
overwriteComment = overwritingMap_1[sid][rubricId].comment;
}
// Add old value
if (oldPoints !== undefined
&& oldPoints !== null
&& !overwritePoints) {
// We have an old points val and we're not overwriting it
// (include the old points value)
params["grade_data[".concat(sid, "][rubric_assessment][").concat(rubricId, "][points]")] = oldPoints;
}
if (oldComment && !overwriteComment) {
// We have an old comment and we're not overwriting it
// (include the old comment)
params["grade_data[".concat(sid, "][rubric_assessment][").concat(rubricId, "][comments]")] = oldComment;
}
});
});
}
// Add rest of grade item updates to params
opts.gradeItems.forEach(function (gradeItem) {
if (gradeItem.rubricId) {
if (gradeItem.points !== undefined) {
params["grade_data[".concat(gradeItem.studentId, "][rubric_assessment][").concat(gradeItem.rubricId, "][points]")] = gradeItem.points;
}
if (gradeItem.comment) {
params["grade_data[".concat(gradeItem.studentId, "][rubric_assessment][").concat(gradeItem.rubricId, "][comments]")] = gradeItem.comment;
}
}
else {
if (gradeItem.points !== undefined) {
params["grade_data[".concat(gradeItem.studentId, "][posted_grade]")] = gradeItem.points;
}
if (gradeItem.comment) {
params["grade_data[".concat(gradeItem.studentId, "][text_comment]")] = gradeItem.comment;
}
}
});
return [4 /*yield*/, this.visitEndpoint({
params: params,
config: config,
action: 'update student grades, comments, and/or rubric assessments for a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_b = opts.courseId) !== null && _b !== void 0 ? _b : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/submissions/update_grades"),
method: 'POST',
})];
case 4:
progress = _c.sent();
if (!opts.waitForCompletion) return [3 /*break*/, 6];
return [4 /*yield*/, (0, waitForCompletion_1.default)({
progress: progress,
visitEndpoint: this.visitEndpoint,
timeoutMin: opts.waitForCompletionTimeout,
})];
case 5:
finishedProgress = _c.sent();
return [2 /*return*/, finishedProgress];
case 6: return [2 /*return*/, progress];
}
});
});
};
/*------------------------------------------------------------------------*/
/* Assignment Override Endpoints */
/*------------------------------------------------------------------------*/
/**
* Gets the list of overrides for an assignment
* @author Gabe Abrams
* @method listOverrides
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment id to look up
* @param {number} [opts.courseId=default course id] Canvas course id to query
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignmentOverride[]>} list of Canvas AssignmentOverrides {@link https://canvas.instructure.com/doc/api/assignments.html#AssignmentOverride}
*/
ECatAssignment.prototype.listOverrides = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'get a list of assignment overrides for a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/overrides"),
method: 'GET',
})];
});
});
};
/**
* Get a specific override on an assignment in a course
* @author Gabe Abrams
* @method getOverride
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment id to query
* @param {number} opts.overrideId Canvas override id to look up
* @param {number} [opts.courseId=default course id] Canvas course id to query
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignmentOverride>} Canvas AssignmentOverride {@link https://canvas.instructure.com/doc/api/assignments.html#AssignmentOverride}
*/
ECatAssignment.prototype.getOverride = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'get a list of assignment overrides for a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/overrides/").concat(opts.overrideId),
method: 'GET',
})];
});
});
};
/**
* Create assignment override. Note that if any dates (dueAt, unlockAt, or
* lockAt) are left out, they will be set to "none" for the target(s) of this
* override. If dueAt is omitted, the target(s) will have no deadline. If
* unlockAt is omitted, the target(s) will immediately be able to see the
* assignment (even if everyone else has to wait until the unlockAt date). If
* lockAt is omitted, the target(s) will be able to submit at any
* time in the future (even if everyone else can't submit because their lock
* date has passed). In short, it is not recommended to omit dates that are
* defined in the assignment.
* @author Gabe Abrams
* @method createOverride
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment id
* @param {number} [opts.courseId=default course id] Canvas course id
* @param {number[]} [opts.studentIds] List of Canvas student IDs to override
* (Note: either studentIds, groupId, or sectionId must be included)
* @param {number} [opts.groupId] Group to override, must be a group
* assignment (Note: either studentIds, groupId, or sectionId must be
* included)
* @param {number} [opts.sectionId] Section to override (Note: either
* studentIds, groupId, or sectionId must be included)
* @param {string} [opts.title=Override for X students] Title of the
* override
* @param {date} [opts.dueAt=no due date] New due date. If excluded, the
* target(s) of this override have no due date (they can submit whenever they
* want without being marked as late)
* @param {date} [opts.unlockAt=no unlock date] New unlock date. If
* excluded, the target(s) of this override can immediately see the assignment
* (their unlock date is the beginning of time)
* @param {date} [opts.lockAt=no lock date] New lock date. If excluded,
* the target(s) of this override can see and submit the assignment at
* any point in the future (their lock date is the end of time)
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignmentOverride>} Canvas AssignmentOverride {@link https://canvas.instructure.com/doc/api/assignments.html#AssignmentOverride}
*/
ECatAssignment.prototype.createOverride = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var title, dueAt, unlockAt, lockAt;
return __generator(this, function (_b) {
title = opts.title;
if (!title) {
title = "Override for ".concat(opts.studentIds.length, " student").concat(utils_1.default.sIfPlural(opts.studentIds.length));
}
dueAt = utils_1.default.includeIfDate(opts.dueAt) || null;
unlockAt = utils_1.default.includeIfDate(opts.unlockAt) || null;
lockAt = utils_1.default.includeIfDate(opts.lockAt) || null;
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'create a new override for a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/overrides"),
method: 'POST',
params: {
'assignment_override[title]': utils_1.default.includeIfTruthy(title),
'assignment_override[student_ids]': utils_1.default.includeIfTruthy(opts.studentIds),
'assignment_override[group_id]': utils_1.default.includeIfTruthy(opts.groupId),
'assignment_override[course_section_id]': utils_1.default.includeIfTruthy(opts.sectionId),
'assignment_override[due_at]': dueAt,
'assignment_override[unlock_at]': unlockAt,
'assignment_override[lock_at]': lockAt,
},
})];
});
});
};
/**
* Update an assignment override. Note: target can only be updated if the
* override is a student override (if this is a group or section override,
* the target remains unchanged).
* Also, note that if any dates (dueAt, unlockAt, or lockAt) are omitted,
* their previous override values will be changed to "none." For instance,
* if the previous override has a dueAt and the update does not, the updated
* override will have no dueAt date (the target(s) of the override will have
* no deadline).
* @author Gabe Abrams
* @method updateOverride
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment id
* @param {number} opts.overrideId the override id to update
* @param {number[]} opts.studentIds List of Canvas student IDs being
* overridden
* @param {number} [opts.courseId=default course id] Canvas course id
* @param {string} [opts.title=current value] New title of the
* override
* @param {date} [opts.dueAt=no due date] New due date. If excluded, the
* target(s) of this override have no due date (they can submit whenever they
* want without being marked as late)
* @param {date} [opts.unlockAt=no unlock date] New unlock date. If
* excluded, the target(s) of this override can immediately see the assignment
* (their unlock date is the beginning of time)
* @param {date} [opts.lockAt=no lock date] New lock date. If excluded,
* the target(s) of this override can see and submit the assignment at
* any point in the future (their lock date is the end of time)
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignmentOverride>} Canvas AssignmentOverride {@link https://canvas.instructure.com/doc/api/assignments.html#AssignmentOverride}
*/
ECatAssignment.prototype.updateOverride = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var dueAt, unlockAt, lockAt;
return __generator(this, function (_b) {
dueAt = utils_1.default.includeIfDate(opts.dueAt) || null;
unlockAt = utils_1.default.includeIfDate(opts.unlockAt) || null;
lockAt = utils_1.default.includeIfDate(opts.lockAt) || null;
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'update an override for a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/overrides/").concat(opts.overrideId),
method: 'PUT',
params: {
'assignment_override[title]': utils_1.default.includeIfTruthy(opts.title),
'assignment_override[student_ids]': utils_1.default.includeIfTruthy(opts.studentIds),
'assignment_override[due_at]': dueAt,
'assignment_override[unlock_at]': unlockAt,
'assignment_override[lock_at]': lockAt,
},
})];
});
});
};
/**
* Deletes an assignment override
* @author Gabe Abrams
* @method deleteOverride
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId Canvas assignment id to query
* @param {number} opts.overrideId Canvas override id to look up
* @param {number} [opts.courseId=default course id] Canvas course id to query
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasAssignmentOverride>} Canvas AssignmentOverride {@link https://canvas.instructure.com/doc/api/assignments.html#AssignmentOverride}
*/
ECatAssignment.prototype.deleteOverride = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'delete an override for a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/overrides/").concat(opts.overrideId),
method: 'DELETE',
})];
});
});
};
/*------------------------------------------------------------------------*/
/* Assignment Submission Endpoints */
/*------------------------------------------------------------------------*/
/**
* Lists the submissions to a specific assignment in a course. If the assignment
* has anonymous grading turned on, to exclude the test user, we will also
* pull the list of students in the course. If including the user object for
* an anonymously graded assignment, fake user objects will be created where
* each submissions[i].user object contains a isAnonymousUser boolean that is
* true
* @author Gabe Abrams
* @method listSubmissions
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId The Canvas assignment Id to query
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {boolean} [opts.includeComments] If truthy, includes all
* comments on submissions
* @param {boolean} [opts.includeRubricAssessment] If truthy,
* includes rubric assessments: breakdown of score for each rubric item
* @param {boolean} [opts.excludeUser] If truthy, excludes
* submission[i].user value with the submission's user information
* @param {boolean} [opts.includeTestStudent] If truthy, includes
* dummy submission by test student (student view) if there is one. Note:
* if anonymous grading is enabled for this assignment, includeTestStudent
* will be true because we don't know which student is the test student
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasSubmission[]>} list of Canvas submissions {@link https://canvas.instructure.com/doc/api/submissions.html#Submission}
*/
ECatAssignment.prototype.listSubmissions = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var fetchUser, subs, realSubs;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
fetchUser = (!opts.includeTestStudent
|| !opts.excludeUser);
return [4 /*yield*/, this.visitEndpoint({
config: config,
action: 'list the submissions to a specific assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/submissions"),
method: 'GET',
params: {
include: utils_1.default.genIncludesList({
submission_comments: opts.includeComments,
rubric_assessment: opts.includeRubricAssessment,
user: fetchUser,
}),
},
})];
case 1:
subs = _b.sent();
// Filter test student if applicable
if (!opts.includeTestStudent) {
// Handle empty list case
if (!subs || subs.length === 0) {
return [2 /*return*/, []];
}
realSubs = subs.filter(function (sub) {
return (!sub.user
|| sub.user.name !== 'Test Student');
});
// Finish
return [2 /*return*/, realSubs];
}
// Not filtering out test student. Just return subs
return [2 /*return*/, subs];
}
});
});
};
/**
* Lists the submissions for a batch of assignment/students in a course
* @author Gabe Abrams
* @method listAllSubmissions
* @memberof api.course.assignment
* @instance
* @async
* @param {object} [opts] object containing all arguments
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {number[]} [opts.studentIds=all students] a list of
* specific students to pull submissions for
* @param {number[]} [opts.assignmentIds=all assignments] a list of
* assignments to get submissions for
* @param {Date} [opts.submittedSince=beginning of time] Exclude
* submissions that were not submitted or were submitted before this date
* @param {Date} [opts.gradedSince=beginning of time] Exclude
* submissions that were not graded or were graded before this date
* @param {string} [opts.workflowState=all workflows] a workflow state
* to filter by. Allowed values: 'submitted', 'unsubmitted', 'graded', or
* 'pending_review'
* @param {string} [opts.enrollmentState=all states except deleted] an
* enrollment state to filter by. Allowed values: 'active' or 'concluded'
* @param {boolean} [opts.includeSubmissionHistory] if true, submission
* history is included
* @param {boolean} [opts.includeComments] if true, includes all comments
* on submissions
* @param {boolean} [opts.includeRubricAssessment] if true,
* rubric assessment is included
* @param {boolean} [opts.includeAssignment] if true, the assignment is
* included for each submission
* @param {boolean} [opts.includeTotalScores] if true, include the total
* scores
* @param {boolean} [opts.includeVisibility] if true, include visibility
* @param {boolean} [opts.includeUser] if true, include the user info
* with each submission
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasSubmission[]>} list of submissions {@link https://canvas.instructure.com/doc/api/submissions.html#Submission}
*/
ECatAssignment.prototype.listAllSubmissions = function (opts, config) {
var _a;
if (opts === void 0) { opts = {}; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'list a batch of submissions in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/students/submissions"),
method: 'GET',
params: {
student_ids: (opts.studentIds
? opts.studentIds
: ['all']),
assignment_ids: opts.assignmentIds,
submitted_since: utils_1.default.includeIfDate(opts.submittedSince),
graded_since: utils_1.default.includeIfDate(opts.gradedSince),
workflow_state: utils_1.default.includeIfTruthy(opts.workflowState),
enrollment_state: utils_1.default.includeIfTruthy(opts.enrollmentState),
include: utils_1.default.genIncludesList({
submission_history: opts.includeSubmissionHistory,
submission_comments: opts.includeComments,
rubric_assessment: opts.includeRubricAssessment,
assignment: opts.includeAssignment,
total_scores: opts.includeTotalScores,
visibility: opts.includeVisibility,
user: opts.includeUser,
}),
},
})];
});
});
};
/**
* Gets a single submission for an assignment
* @author Gabe Abrams
* @method getSubmission
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId The Canvas assignment Id
* @param {number} opts.studentId The Canvas student Id
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {boolean} [opts.includeComments] If truthy, includes all
* comments on submissions
* @param {boolean} [opts.includeRubricAssessment] If truthy,
* includes rubric assessments: breakdown of score for each rubric item
* @param {boolean} [opts.excludeUser] If truthy, excludes
* submission[i].user value with the submission's user information
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasSubmission>} Canvas submission {@link https://canvas.instructure.com/doc/api/submissions.html#Submission}
*/
ECatAssignment.prototype.getSubmission = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'get a specific submission to an assignment in a course',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/submissions/").concat(opts.studentId),
method: 'GET',
params: {
include: utils_1.default.genIncludesList({
submission_comments: opts.includeComments,
rubric_assessment: opts.includeRubricAssessment,
user: !opts.excludeUser,
}),
},
})];
});
});
};
/**
* Creates a text submission on behalf of the current user
* @author Gabe Abrams
* @method createTextSubmission
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId The Canvas assignment Id
* @param {string} opts.text The text body of the submission
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {string} [opts.comment] A text student comment to include
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasSubmission>} Canvas submission {@link https://canvas.instructure.com/doc/api/submissions.html#Submission}
*/
ECatAssignment.prototype.createTextSubmission = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'create a text submission to a specific assignment in a course on behalf of the current user',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/submissions"),
method: 'POST',
params: {
'comment[text_comment]': utils_1.default.includeIfTruthy(opts.comment),
'submission[body]': opts.text,
'submission[submission_type]': 'online_text_entry',
},
})];
});
});
};
/**
* Creates a url submission on behalf of the current user
* @author Gabe Abrams
* @method createURLSubmission
* @memberof api.course.assignment
* @instance
* @async
* @param {object} opts object containing all arguments
* @param {number} opts.assignmentId The Canvas assignment Id
* @param {string} opts.url The url of the submission
* @param {number} [opts.courseId=default course id] Canvas course Id
* @param {string} [opts.comment] A text student comment to include
* @param {APIConfig} [config] custom configuration for this specific endpoint
* call (overwrites defaults that were included when api was initialized)
* @returns {Promise<CanvasSubmission>} Canvas submission {@link https://canvas.instructure.com/doc/api/submissions.html#Submission}
*/
ECatAssignment.prototype.createURLSubmission = function (opts, config) {
var _a;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.visitEndpoint({
config: config,
action: 'create a url submission to a specific assignment in a course on behalf of the current user',
path: "".concat(API_PREFIX_1.default, "/courses/").concat((_a = opts.courseId) !== null && _a !== void 0 ? _a : this.defaultCourseId, "/assignments/").concat(opts.assignmentId, "/submissions"),
method: 'POST',
params: {
'comment[text_comment]': utils_1.default.includeIfTruthy(opts.comment),
'submission[url]': opts.url,
'submission[submission_type]': 'online_url',
},
})];
});
});
};
return ECatAssignment;
}(EndpointCategory_1.default));
/*------------------------------------------------------------------------*/
/* Export */
/*------------------------------------------------------------------------*/
exports.default = ECatAssignment;
//# sourceMappingURL=ECatAssignment.js.map