package com.instructure.canvasapi.api; import android.content.Context; import android.text.TextUtils; import com.instructure.canvasapi.model.Attachment; import com.instructure.canvasapi.model.CanvasContext; import com.instructure.canvasapi.model.FileUploadParams; import com.instructure.canvasapi.model.LTITool; import com.instructure.canvasapi.model.RubricAssessment; import com.instructure.canvasapi.model.RubricCriterionRating; import com.instructure.canvasapi.model.StudentSubmission; import com.instructure.canvasapi.model.Submission; import com.instructure.canvasapi.utilities.APIHelpers; import com.instructure.canvasapi.utilities.CanvasCallback; import com.instructure.canvasapi.utilities.ExhaustiveBridgeCallback; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import retrofit.Callback; import retrofit.http.Body; import retrofit.http.GET; import retrofit.http.Multipart; import retrofit.http.POST; import retrofit.http.PUT; import retrofit.http.Part; import retrofit.http.PartMap; import retrofit.http.Path; import retrofit.http.Query; import retrofit.http.QueryMap; import retrofit.mime.TypedFile; /** * Created by Brady Larson on 9/9/13. * * Copyright (c) 2014 Instructure. All rights reserved. */ public class SubmissionAPI extends BuildInterfaceAPI { public interface SubmissionsInterface { @GET("/{context_id}/assignments/{assignmentID}/submissions?include[]=submission_comments") void getSubmissionsWithComments(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, Callback<Submission[]> callback); @GET("/{context_id}/assignments/{assignmentID}/submissions?include[]=submission_history") void getSubmissionsWithHistory(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, Callback<Submission[]> callback); @GET("/{context_id}/assignments/{assignmentID}/submissions?include[]=submission_comments&include[]=submission_history") void getSubmissionsWithCommentsAndHistory(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, Callback<Submission[]> callback); @GET("/{context_id}/assignments/{assignmentID}/submissions?include[]=submission_comments&include[]=submission_history&include[]=rubric_assessment&include[]=user&include[]=group") void getSubmissionsWithCommentsHistoryAndRubric(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, Callback<Submission[]> callback); @GET("/{context_id}/assignments/{assignmentID}/submissions/{submissionID}?include[]=rubric_assessment") void getSubmission(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Path("submissionID") long submissionID, Callback<Submission> callback); @GET("/{context_id}/assignments/{assignmentID}/submissions/{submissionID}?include[]=rubric_assessment&include[]=submission_comments&include[]=submission_history") void getSubmissionWithCommentsAndHistory(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Path("submissionID") long userID, Callback<Submission> callback); @GET("/{context_id}/assignments/{assignmentID}/submissions/{submissionID}?include[]=rubric_assessment&include[]=submission_comments&include[]=submission_history&include[]=user") void getUserSubmissionWithCommentsHistoryAndRubric(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Path("submissionID") long userID, Callback<Submission> callback); @GET("/{context_id}/students/submissions?include[]=assignment") void getSubmissionsForMultipleStudents(@Path("context_id") long context_id, @Query("student_ids[]") String ids, Callback<Submission[]> callback); @GET("/{context_id}/students/submissions?grouped=true&include[]=total_scores") void getSubmissionsAndGradesForMultipleStudents(@Path("context_id") long context_id, @Query("student_ids[]") String ids, Callback<StudentSubmission[]> callback); @GET("/{context_id}/students/submissions") void getSubmissions(@Path("context_id") long context_id, Callback<Submission[]> callback); @GET("/{next}") void getNextPageSubmissions(@Path(value = "next", encode = false) String nextURL, Callback<Submission[]> callback); @PUT("/{context_id}/assignments/{assignmentID}/submissions/{userID}") void postSubmissionComment(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Path("userID") long userID, @Query("comment[text_comment]") String comment, @Body String body, Callback<Submission> callback); @PUT("/{context_id}/assignments/{assignmentID}/submissions/{userID}") void postMediaSubmissionComment(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Path("userID") long userID, @Query("comment[media_comment_id]") String media_id, @Query("comment[media_comment_type]") String commentType, @Body String body, Callback<Submission> callback); @POST("/{context_id}/assignments/{assignmentID}/submissions") void postTextSubmission(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Query("submission[submission_type]") String submissionType, @Query("submission[body]") String text, @Body String body, Callback<Submission> callback); @POST("/{context_id}/assignments/{assignmentID}/submissions") void postURLSubmission(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Query("submission[submission_type]") String submissionType, @Query("submission[url]") String url, @Body String body, Callback<Submission> callback); @POST("/{context_id}/assignments/{assignmentID}/submissions") void postMediaSubmission(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Query("submission[submission_type]") String submissionType, @Query("submission[media_comment_id]") String kalturaId,@Query("submission[media_comment_type]") String mediaType, @Body String body, CanvasCallback<Submission> callback); @GET("/{path}") void getLTIFromAuthenticationURL(@Path(value = "path", encode = false) String url, Callback<LTITool> callback); @PUT("/{context_id}/assignments/{assignmentID}/submissions/{userID}") void postSubmissionRubricAssessmentMap(@Path("context_id") long context_id, @Path("assignmentID") long assignmentID, @Path("userID") long userID, @QueryMap Map<String, String> rubricAssessment, @Query("submission[posted_grade]") String assignmentScore, @Body String body, Callback<Submission> callback); ///////////////////////////////////////////////////////////////////////////// // Synchronous ///////////////////////////////////////////////////////////////////////////// @POST("/courses/{courseId}/assignments/{assignmentId}/submissions/self/files") FileUploadParams getFileUploadParams(@Path("courseId") long courseId, @Path("assignmentId") long assignmentId, @Query("size") long size, @Query("name") String fileName, @Query("content_type") String content_type, @Body String body); @Multipart @POST("/") Attachment uploadCourseFile(@PartMap LinkedHashMap<String, String> params, @Part("file") TypedFile file); @POST("/courses/{courseId}/assignments/{assignmentID}/submissions") Submission postSubmissionAttachments(@Path("courseId") long courseId, @Path("assignmentID") long assignmentID, @Query("submission[submission_type]") String submissionType, @Query("submission[file_ids][]") ArrayList<String> attachments, @Body String body); } ///////////////////////////////////////////////////////////////////////// // API Calls ///////////////////////////////////////////////////////////////////////// public static void getSubmissionsWithComments(CanvasContext canvasContext, long assignmentID, final CanvasCallback<Submission[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithComments(canvasContext.getId(), assignmentID, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithComments(canvasContext.getId(), assignmentID, callback); } public static void getSubmissionsWithHistory(CanvasContext canvasContext, long assignmentID, final CanvasCallback<Submission[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithHistory(canvasContext.getId(), assignmentID, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithHistory(canvasContext.getId(), assignmentID, callback); } public static void getSubmissionsWithCommentsAndHistory(CanvasContext canvasContext, long assignmentID, final CanvasCallback<Submission[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithCommentsAndHistory(canvasContext.getId(), assignmentID, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithCommentsAndHistory(canvasContext.getId(), assignmentID, callback); } public static void getSubmissionsWithCommentsHistoryAndRubric(CanvasContext canvasContext, long assignmentID, final CanvasCallback<Submission[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithCommentsHistoryAndRubric(canvasContext.getId(), assignmentID, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithCommentsHistoryAndRubric(canvasContext.getId(), assignmentID, callback); } public static void getSubmission(CanvasContext canvasContext, long assignmentID, long userID, final CanvasCallback<Submission> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmission(canvasContext.getId(), assignmentID, userID, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmission(canvasContext.getId(), assignmentID, userID, callback); } public static void getSubmissions(CanvasContext canvasContext, final CanvasCallback<Submission[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissions(canvasContext.getId(), callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissions(canvasContext.getId(), callback); } public static void getSubmissionsExhaustive(CanvasContext canvasContext, final CanvasCallback<Submission[]> callback) { if (APIHelpers.paramIsNull(callback)) { return; } CanvasCallback<Submission[]> bridge = new ExhaustiveBridgeCallback<>(Submission.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() { @Override public void performApiCallWithExhaustiveCallback(CanvasCallback callback, String nextUrl, boolean isCached) { SubmissionAPI.getNextPageSubmissionsChained(nextUrl, callback, isCached); } }); buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissions(canvasContext.getId(), bridge); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissions(canvasContext.getId(), bridge); } public static void getNextPageSubmissions(String nextURL, CanvasCallback callback){ if (APIHelpers.paramIsNull(callback, nextURL)) { return; } callback.setIsNextPage(true); buildCacheInterface(SubmissionsInterface.class, callback, null).getNextPageSubmissions(nextURL, callback); buildInterface(SubmissionsInterface.class, callback, null).getNextPageSubmissions(nextURL, callback); } public static void getNextPageSubmissionsChained(String nextURL, CanvasCallback callback, boolean isCache){ if (APIHelpers.paramIsNull(callback, nextURL)) { return; } callback.setIsNextPage(true); if (isCache) { buildCacheInterface(SubmissionsInterface.class, callback, false).getNextPageSubmissions(nextURL, callback); } else { buildInterface(SubmissionsInterface.class, callback, false).getNextPageSubmissions(nextURL, callback); } } public static void getSubmissionWithCommentsAndHistoryChained(CanvasContext canvasContext, long assignmentID, long userID, final CanvasCallback<Submission> callback, boolean isCached) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } if (isCached) { buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionWithCommentsAndHistory(canvasContext.getId(), assignmentID, userID, callback); } else { buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionWithCommentsAndHistory(canvasContext.getId(), assignmentID, userID, callback); } } public static void getSubmissionsWithCommentsHistoryAndRubricExhaustive(CanvasContext canvasContext, long assignmentID, final CanvasCallback<Submission[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } CanvasCallback<Submission[]> bridge = new ExhaustiveBridgeCallback<>(Submission.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() { @Override public void performApiCallWithExhaustiveCallback(CanvasCallback bridgeCallback, String nextUrl, boolean isCached) { if(callback.isCancelled()){ return; } SubmissionAPI.getNextPageSubmissionsChained(nextUrl, bridgeCallback, isCached); } }); buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithCommentsHistoryAndRubric(canvasContext.getId(), assignmentID, bridge); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsWithCommentsHistoryAndRubric(canvasContext.getId(), assignmentID, bridge); } public static void getSubmissionWithCommentsAndHistory(CanvasContext canvasContext, long assignmentID, long userID, final CanvasCallback<Submission> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionWithCommentsAndHistory(canvasContext.getId(), assignmentID, userID, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionWithCommentsAndHistory(canvasContext.getId(), assignmentID, userID, callback); } public static void getUserSubmissionWithCommentsHistoryAndRubric(CanvasContext canvasContext, long assignmentID, long userID, final CanvasCallback<Submission> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getUserSubmissionWithCommentsHistoryAndRubric(canvasContext.getId(), assignmentID, userID, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getUserSubmissionWithCommentsHistoryAndRubric(canvasContext.getId(), assignmentID, userID, callback); } public static void postSubmissionComment(CanvasContext canvasContext, long assignmentID, long userID, String comment, final CanvasCallback<Submission> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildInterface(SubmissionsInterface.class, callback, canvasContext).postSubmissionComment(canvasContext.getId(), assignmentID, userID, comment, "", callback); } public static void postMediaSubmissionComment(CanvasContext canvasContext, long assignmentID, long userID, String kalturaMediaId, String mediaType, final CanvasCallback<Submission> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildInterface(SubmissionsInterface.class, callback, canvasContext).postMediaSubmissionComment(canvasContext.getId(), assignmentID, userID, kalturaMediaId, mediaType, "", callback); } public static void postTextSubmission(CanvasContext canvasContext, long assignmentID, String submissionType, String text, final CanvasCallback<Submission> callback) { if (APIHelpers.paramIsNull(callback, submissionType, text, canvasContext)) { return; } buildInterface(SubmissionsInterface.class, callback, canvasContext).postTextSubmission(canvasContext.getId(), assignmentID, submissionType, text, "", callback); } public static void postURLSubmission(CanvasContext canvasContext, long assignmentID, String submissionType, String url, final CanvasCallback<Submission> callback) { if (APIHelpers.paramIsNull(callback, submissionType, url, canvasContext)) { return; } buildInterface(SubmissionsInterface.class, callback, canvasContext).postURLSubmission(canvasContext.getId(), assignmentID, submissionType, url, "", callback); } public static void postMediaSubmission(CanvasContext canvasContext, long assignmentID, String submissionType, String kalturaId, String mediaType, final CanvasCallback<Submission> callback){ if (APIHelpers.paramIsNull(callback, submissionType, kalturaId, canvasContext)) { return; } buildInterface(SubmissionsInterface.class, callback, canvasContext).postMediaSubmission(canvasContext.getId(), assignmentID, submissionType, kalturaId, mediaType, "", callback); } public static void getLTIFromAuthenticationURL(String url, final CanvasCallback<LTITool> callback) { if (APIHelpers.paramIsNull(callback, url)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, null, false).getLTIFromAuthenticationURL(url, callback); buildInterface(SubmissionsInterface.class, callback, null, false).getLTIFromAuthenticationURL(url, callback); } public static void getLTIFromAuthenticationURLChained(String url, final CanvasCallback<LTITool> callback, boolean isCached) { if (APIHelpers.paramIsNull(callback, url)) { return; } if (isCached) { buildCacheInterface(SubmissionsInterface.class, callback, null, false).getLTIFromAuthenticationURL(url, callback); } else { buildInterface(SubmissionsInterface.class, callback, null, false).getLTIFromAuthenticationURL(url, callback); } } /** * * @param canvasContext * @param callback * @param ids -- a list of comma separated ids or "all" if you want to get all available submissions */ public static void getSubmissionsForMultipleStudents(CanvasContext canvasContext, CanvasCallback<Submission[]> callback, String ids) { if (APIHelpers.paramIsNull(callback, canvasContext, ids)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsForMultipleStudents(canvasContext.getId(), ids, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsForMultipleStudents(canvasContext.getId(), ids, callback); } /** * * @param canvasContext * @param callback * @param ids -- a list of comma separated ids or "all" if you want to get all available submissions */ public static void getSubmissionsAndGradesForMultipleStudents(CanvasContext canvasContext, String ids, CanvasCallback<StudentSubmission[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext, ids)) { return; } buildCacheInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsAndGradesForMultipleStudents(canvasContext.getId(), ids, callback); buildInterface(SubmissionsInterface.class, callback, canvasContext).getSubmissionsAndGradesForMultipleStudents(canvasContext.getId(), ids, callback); } public static void postSubmissionRubricAssessmentMap(CanvasContext canvasContext, RubricAssessment rubricAssessment, String assignmentScore, long assignmentId, long userId, CanvasCallback<Submission> callback){ if (APIHelpers.paramIsNull(canvasContext, rubricAssessment, callback)){return;} buildInterface(SubmissionsInterface.class, callback, canvasContext).postSubmissionRubricAssessmentMap(canvasContext.getId(), assignmentId, userId, generateRubricAssessmentQueryMap(rubricAssessment), assignmentScore, "", callback); } public static void postSubmissionRubricAssessmentMap(CanvasContext canvasContext, HashMap<String, RubricCriterionRating> rubricAssessment, String assignmentScore, long assignmentId, long userId, CanvasCallback<Submission> callback){ if (APIHelpers.paramIsNull(canvasContext, rubricAssessment, callback)){return;} buildInterface(SubmissionsInterface.class, callback, canvasContext).postSubmissionRubricAssessmentMap(canvasContext.getId(), assignmentId, userId, generateRubricAssessmentQueryMap(rubricAssessment), assignmentScore, "", callback); } /** * We generate a map given a rubric assessment in order to save a submission assessment with retrofit * * Rubric Assessment points can be rewarded in the form: * - rubric_assessment[criterion_id][points] * * Rubric Assessment comments can be rewarded in the form: * - rubric_assessment[criterion_id][comments] * * Example assessment : * - rubric_assessment[crit1][points]=3&rubric_assessment[crit2][points]=5&rubric_assessment[crit2][comments]=Well%20Done. */ private static final String assessmentPrefix = "rubric_assessment["; private static final String pointsPostFix = "][points]"; private static final String commentsPostFix = "][comments]"; private static Map<String, String> generateRubricAssessmentQueryMap(HashMap<String, RubricCriterionRating> rubricAssessment){ Map<String, String> map = new HashMap<>(); for (Map.Entry<String, RubricCriterionRating> entry : rubricAssessment.entrySet()) { RubricCriterionRating rating = entry.getValue(); map.put(assessmentPrefix +rating.getCriterionId() +pointsPostFix, String.valueOf(rating.getPoints())); if(rating.getComments() != null && !TextUtils.isEmpty(rating.getComments())){ map.put(assessmentPrefix +rating.getCriterionId() +commentsPostFix, rating.getComments()); } } return map; } private static Map<String, String> generateRubricAssessmentQueryMap(RubricAssessment rubricAssessment){ Map<String, String> map = new HashMap<>(); for (RubricCriterionRating entry : rubricAssessment.getRatings()) { map.put(assessmentPrefix +entry.getCriterionId() +pointsPostFix, String.valueOf(entry.getPoints())); if(entry.getComments() != null && !TextUtils.isEmpty(entry.getComments())){ map.put(assessmentPrefix +entry.getCriterionId() +commentsPostFix, entry.getComments()); } } return map; } ///////////////////////////////////////////////////////////////////////////// // Synchronous ///////////////////////////////////////////////////////////////////////////// public static FileUploadParams getFileUploadParams(Context context, long courseId, long assignmentId, String fileName, long size, String contentType){ return buildInterface(SubmissionsInterface.class, context).getFileUploadParams(courseId, assignmentId, size, fileName, contentType, ""); } public static Attachment uploadAssignmentSubmission(String uploadUrl, LinkedHashMap<String,String> uploadParams, String mimeType, File file){ return buildUploadInterface(SubmissionsInterface.class, uploadUrl).uploadCourseFile(uploadParams, new TypedFile(mimeType, file)); } public static Submission postSubmissionAttachments(Context context, long courseId, long assignmentId, ArrayList<String> attachments){ return buildInterface(SubmissionsInterface.class, context).postSubmissionAttachments(courseId, assignmentId, "online_upload", attachments, ""); } }