package com.instructure.canvasapi.api; import android.content.Context; import android.util.Log; import com.instructure.canvasapi.model.Attachment; import com.instructure.canvasapi.model.CanvasColor; import com.instructure.canvasapi.model.CanvasContext; import com.instructure.canvasapi.model.Domain; import com.instructure.canvasapi.model.Enrollment; import com.instructure.canvasapi.model.FileUploadParams; import com.instructure.canvasapi.model.Parent; import com.instructure.canvasapi.model.ParentResponse; import com.instructure.canvasapi.model.ParentWrapper; import com.instructure.canvasapi.model.ResetParent; import com.instructure.canvasapi.model.Student; import com.instructure.canvasapi.model.User; import com.instructure.canvasapi.utilities.APIHelpers; import com.instructure.canvasapi.utilities.CanvasCallback; import com.instructure.canvasapi.utilities.ExhaustiveBridgeCallback; import com.instructure.canvasapi.utilities.Masquerading; import com.instructure.canvasapi.utilities.UserCallback; import org.json.JSONObject; import java.io.File; import java.util.LinkedHashMap; import retrofit.Callback; import retrofit.client.Response; import retrofit.http.Body; import retrofit.http.DELETE; 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.mime.TypedFile; /** * Copyright (c) 2015 Instructure. All rights reserved. */ public class UserAPI extends BuildInterfaceAPI { public enum ENROLLMENT_TYPE {STUDENT, TEACHER, TA, OBSERVER, DESIGNER} interface UsersInterface { @GET("/users/self/profile") void getSelf(Callback<User> callback); // TODO: We probably need to create a helper that does each of these individually @GET("/users/self/enrollments?state[]=active&state[]=invited&state[]=completed") void getSelfEnrollments(Callback<Enrollment[]> callback); @GET("/users/self") void getSelfWithPermission(CanvasCallback<User> callback); @PUT("/users/self") void updateShortName(@Query("user[short_name]") String shortName, @Body String body, Callback<User> callback); @GET("/users/{userid}/profile") void getUserById(@Path("userid")long userId, Callback<User> userCallback); @GET("/{context_id}/users/{userId}?include[]=avatar_url&include[]=user_id&include[]=email&include[]=bio") void getUserById(@Path("context_id") long context_id, @Path("userId")long userId, Callback<User> userCallback); @GET("/{context_id}/users?include[]=enrollments&include[]=avatar_url&include[]=user_id&include[]=email&include[]=bio") void getFirstPagePeopleList(@Path("context_id") long context_id, Callback<User[]> callback); @GET("/{context_id}/users?include[]=enrollments&include[]=avatar_url&include[]=user_id&include[]=email") void getFirstPagePeopleListWithEnrollmentType(@Path("context_id") long context_id, @Query("enrollment_type") String enrollmentType, Callback<User[]> callback); @GET("/{next}") void getNextPagePeopleList(@Path(value = "next", encode = false) String nextURL, Callback<User[]> callback); @POST("/users/self/file") void uploadUserFileURL( @Query("url") String fileURL, @Query("name") String fileName, @Query("size") long size, @Query("content_type") String content_type, @Query("parent_folder_path") String parentFolderPath, @Body String body, Callback<String> callback); @POST("/users/self/files") FileUploadParams getFileUploadParams( @Query("size") long size, @Query("name") String fileName, @Query("content_type") String content_type, @Query("parent_folder_id") Long parentFolderId, @Body String body); @POST("/users/self/files") FileUploadParams getFileUploadParams( @Query("size") long size, @Query("name") String fileName, @Query("content_type") String content_type, @Query("parent_folder_path") String parentFolderPath, @Body String body); @Multipart @POST("/") Attachment uploadUserFile(@PartMap LinkedHashMap<String, String> params, @Part("file") TypedFile file); //Colors @GET("/users/self/colors") void getColors(CanvasCallback<CanvasColor> callback); @PUT("/users/self/colors/{context_id}") void setColor(@Path("context_id") String context_id, @Query(value = "hexcode", encodeValue = false) String color, @Body String body, CanvasCallback<CanvasColor> callback); @POST("/accounts/{account_id}/self_registration") void createSelfRegistrationUser(@Path("account_id") long account_id, @Query("user[name]") String userName, @Query("pseudonym[unique_id]") String emailAddress, @Query("user[terms_of_use]") int acceptsTerms, @Body String body, Callback<User> callback); @POST("/users/self/observees") void addObserveeWithToken(@Query("access_token") String token, @Body String body, CanvasCallback<User> callback); @GET("/users/self/observees?include[]=avatar_url") void getObservees(CanvasCallback<User[]> callback); @DELETE("/users/self/observees/{observee_id}") void removeObservee(@Path("observee_id") long observee_id, Callback<User> callback); @DELETE("/student/{observer_id}/{student_id}") void removeStudent(@Path("observer_id") String observer_id, @Path("student_id") String student_id, Callback<Response> callback); @PUT("/newparent") void addParent(@Body ParentWrapper body, Callback<ParentResponse> callback); @GET("/account/{observer_username}") void getParentUserDomain(@Path("observer_username") String email, Callback<Domain> callback); @POST("/authenticate") void authenticateParent(@Body Parent body, Callback<ParentResponse> callback); @GET("/students/{observer_id}") void getObserveesForParent(@Path("observer_id") String observerId, CanvasCallback<Student[]> callback); @GET("/add_student/{observer_id}") void addStudentToParent(@Path("observer_id") String observerId, @Query(value = "student_domain", encodeValue = false) String studentDomain, CanvasCallback<Response> callback); @POST("/send_password_reset/{userName}") void sendPasswordResetForParent(@Path(value = "userName", encode = false) String userName, @Body JSONObject body, CanvasCallback<Response> callback); @POST("/reset_password") void resetParentPassword(@Body Parent parent, CanvasCallback<ResetParent> callback); } ///////////////////////////////////////////////////////////////////////// // API Calls ///////////////////////////////////////////////////////////////////////// public static void getSelf(UserCallback callback) { if (APIHelpers.paramIsNull(callback)) { return; } //Read cache callback.cache(APIHelpers.getCacheUser(callback.getContext()), null, null); //Don't allow this API call to be made while masquerading. //It causes the current user to be overridden with the masqueraded one. if (Masquerading.isMasquerading(callback.getContext())) { Log.w(APIHelpers.LOG_TAG,"No API call for /users/self/profile can be made while masquerading."); return; } buildInterface(UsersInterface.class, callback, null).getSelf(callback); } public static void getSelfWithPermissions(CanvasCallback<User> callback) { if (APIHelpers.paramIsNull(callback)) { return; } //Don't allow this API call to be made while masquerading. //It causes the current user to be overriden with the masqueraded one. if (Masquerading.isMasquerading(callback.getContext())) { Log.w(APIHelpers.LOG_TAG,"No API call for /users/self can be made while masquerading."); return; } buildCacheInterface(UsersInterface.class, callback, null).getSelfWithPermission(callback); buildInterface(UsersInterface.class, callback, null).getSelfWithPermission(callback); } public static void getSelfEnrollments(CanvasCallback<Enrollment[]> callback) { if(APIHelpers.paramIsNull(callback)) return; buildCacheInterface(UsersInterface.class, callback, null).getSelfEnrollments(callback); buildInterface(UsersInterface.class, callback, null).getSelfEnrollments(callback); } public static void updateShortName(String shortName, CanvasCallback<User> callback) { if (APIHelpers.paramIsNull(callback, shortName)) { return; } buildInterface(UsersInterface.class, callback, null).updateShortName(shortName, "", callback); } public static void getUserById(long userId, CanvasCallback<User> userCanvasCallback){ if(APIHelpers.paramIsNull(userCanvasCallback)){return;} buildCacheInterface(UsersInterface.class, userCanvasCallback, null).getUserById(userId, userCanvasCallback); //Passing UserCallback here will break OUR cache. if(userCanvasCallback instanceof UserCallback){ Log.e(APIHelpers.LOG_TAG, "You cannot pass a User Call back here. It'll break cache for users/self.."); return; } buildInterface(UsersInterface.class, userCanvasCallback, null).getUserById(userId, userCanvasCallback); } public static void getUserByIdNoCache(long userId, CanvasCallback<User> userCanvasCallback){ if(APIHelpers.paramIsNull(userCanvasCallback)){return;} //Passing UserCallback here will break OUR cache. if(userCanvasCallback instanceof UserCallback){ Log.e(APIHelpers.LOG_TAG, "You cannot pass a User Call back here. It'll break cache for users/self.."); return; } buildInterface(UsersInterface.class, userCanvasCallback, null).getUserById(userId, userCanvasCallback); } public static void getCourseUserById(CanvasContext canvasContext, long userId, CanvasCallback<User> userCanvasCallback){ if(APIHelpers.paramIsNull(userCanvasCallback)){return;} buildCacheInterface(UsersInterface.class, userCanvasCallback, canvasContext).getUserById(canvasContext.getId(), userId, userCanvasCallback); //Passing UserCallback here will break OUR cache. if(userCanvasCallback instanceof UserCallback){ Log.e(APIHelpers.LOG_TAG, "You cannot pass a User Call back here. It'll break cache for users/self.."); return; } buildInterface(UsersInterface.class, userCanvasCallback, canvasContext).getUserById(canvasContext.getId(), userId, userCanvasCallback); } public static void getFirstPagePeople(CanvasContext canvasContext, CanvasCallback<User[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleList(canvasContext.getId(), callback); buildInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleList(canvasContext.getId(), callback); } public static void getFirstPagePeopleChained(CanvasContext canvasContext, boolean isCached, CanvasCallback<User[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } if(isCached) { buildCacheInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleList(canvasContext.getId(), callback); } else { buildInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleList(canvasContext.getId(), callback); } } public static void getNextPagePeople(String nextURL, CanvasCallback<User[]> callback){ if (APIHelpers.paramIsNull(callback, nextURL)) { return; } callback.setIsNextPage(true); buildCacheInterface(UsersInterface.class, callback, false).getNextPagePeopleList(nextURL, callback); buildInterface(UsersInterface.class, callback, false).getNextPagePeopleList(nextURL, callback); } public static void getNextPagePeopleChained(String nextURL, CanvasCallback<User[]> callback, boolean isCached){ if (APIHelpers.paramIsNull(callback, nextURL)) { return; } callback.setIsNextPage(true); if (isCached) { buildCacheInterface(UsersInterface.class, callback, false).getNextPagePeopleList(nextURL, callback); } else { buildInterface(UsersInterface.class, callback, false).getNextPagePeopleList(nextURL, callback); } } public static void getAllUsersForCourseByEnrollmentType(CanvasContext canvasContext, ENROLLMENT_TYPE enrollment_type, final CanvasCallback<User[]> callback){ if(APIHelpers.paramIsNull(callback, canvasContext)){return;} CanvasCallback<User[]> bridge = new ExhaustiveBridgeCallback<>(User.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() { @Override public void performApiCallWithExhaustiveCallback(CanvasCallback bridgeCallback, String nextURL, boolean isCached) { if(callback.isCancelled()) { return; } UserAPI.getNextPagePeopleChained(nextURL, bridgeCallback, isCached); } }); buildCacheInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleListWithEnrollmentType(canvasContext.getId(), getEnrollmentTypeString(enrollment_type), bridge); buildInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleListWithEnrollmentType(canvasContext.getId(), getEnrollmentTypeString(enrollment_type), bridge); } public static void getFirstPagePeople(CanvasContext canvasContext, ENROLLMENT_TYPE enrollment_type, CanvasCallback<User[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } buildCacheInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleListWithEnrollmentType(canvasContext.getId(), getEnrollmentTypeString(enrollment_type), callback); buildInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleListWithEnrollmentType(canvasContext.getId(), getEnrollmentTypeString(enrollment_type), callback); } public static void getFirstPagePeopleChained(CanvasContext canvasContext, ENROLLMENT_TYPE enrollment_type, boolean isCached, CanvasCallback<User[]> callback) { if (APIHelpers.paramIsNull(callback, canvasContext)) { return; } if(isCached) { buildCacheInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleListWithEnrollmentType(canvasContext.getId(), getEnrollmentTypeString(enrollment_type), callback); } else { buildInterface(UsersInterface.class, callback, canvasContext).getFirstPagePeopleListWithEnrollmentType(canvasContext.getId(), getEnrollmentTypeString(enrollment_type), callback); } } public static void getColors(Context context, CanvasCallback<CanvasColor> callback) { buildCacheInterface(UsersInterface.class, context, false).getColors(callback); buildInterface(UsersInterface.class, context, false).getColors(callback); } public static void setColor(Context context, CanvasContext canvasContext, int color, CanvasCallback<CanvasColor> callback) { if (APIHelpers.paramIsNull(context, canvasContext, callback)) { return; } setColor(context, canvasContext.getContextId(), color, callback); } public static void setColor(Context context, String context_id, int color, CanvasCallback<CanvasColor> callback) { if (APIHelpers.paramIsNull(context, context_id, callback)) { return; } //Modifies a color into a RRGGBB color string with no #. String hexColor = Integer.toHexString(color); hexColor = hexColor.substring(hexColor.length() - 6); if(hexColor.contains("#")) { hexColor = hexColor.replaceAll("#", ""); } buildInterface(UsersInterface.class, context, false).setColor(context_id, hexColor, "", callback); } public static void createSelfRegistrationUser(long accountId, String userName, String emailAddress, CanvasCallback<User> callback) { if (APIHelpers.paramIsNull(userName, emailAddress, callback)) { return; } buildInterface(UsersInterface.class, callback, false).createSelfRegistrationUser(accountId, userName, emailAddress, 1, "", callback); } public static void addObserveeByToken(String token, CanvasCallback<User> callback) { if(APIHelpers.paramIsNull(token, callback)) { return; } buildInterface(UsersInterface.class, callback, false).addObserveeWithToken(token, "", callback); } public static void getObservees(CanvasCallback<User[]> callback) { if(APIHelpers.paramIsNull(callback)) { return; } buildCacheInterface(UsersInterface.class, callback).getObservees(callback); buildInterface(UsersInterface.class, callback).getObservees(callback); } public static void removeObservee(long observeeId, CanvasCallback<User> callback) { if(APIHelpers.paramIsNull(callback)) { return; } buildInterface(UsersInterface.class, callback).removeObservee(observeeId, callback); } /** * Remove student from Airwolf. Currently only used in the Parent App * * @param observerId * @param studentId * @param callback - 200 if successful */ public static void removeStudent(String observerId, String studentId, CanvasCallback<Response> callback) { if(APIHelpers.paramIsNull(callback)) { return; } buildInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback).removeStudent(observerId, studentId, callback); } /** * Add parent to Airwolf/Canvas. Currently only used in the Parent App. * @param body * @param callback */ public static void addParent(Parent body, CanvasCallback<ParentResponse> callback) { if(APIHelpers.paramIsNull(body, callback)) { return; } ParentWrapper parentWrapper = new ParentWrapper(); parentWrapper.setParent(body); buildInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback, false).addParent(parentWrapper, callback); } /** * Get the parent's domain based on their email from Airwolf. Currently only used in the Parent App. * @param email - Parent's username * @param callback */ public static void getParentUserDomain(String email, CanvasCallback<Domain> callback) { if(APIHelpers.paramIsNull(email, callback)) { return; } buildInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback).getParentUserDomain(email, callback); } public static void authenticateParent(String email, String password, CanvasCallback<ParentResponse> callback) { if(APIHelpers.paramIsNull(email, password, callback)) { return; } Parent parent = new Parent(); parent.setUsername(email); parent.setPassword(password); buildInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback, false).authenticateParent(parent, callback); } public static void getObserveesForParent(String parentId, CanvasCallback<Student[]> callback) { if(APIHelpers.paramIsNull(parentId, callback)) { return; } buildCacheInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback).getObserveesForParent(parentId, callback); buildInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback).getObserveesForParent(parentId, callback); } /** * Add a student to a parent's account so the parent can observe the student * * @param parentId - ID of the parent * @param studentDomain - Domain of the student * @param callback */ public static void addStudentToParent(String parentId, String studentDomain, CanvasCallback<Response> callback) { if(APIHelpers.paramIsNull(parentId, studentDomain, callback)) { return; } buildInterfaceNoRedirects(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback, false).addStudentToParent(parentId, studentDomain, callback); } /** * Let the user request a password if they forgot it. * * Will return a 404 if there is no record of the e-mail address. * * @param userName The user's email address * @param callback */ public static void sendPasswordResetForParent(String userName, CanvasCallback<Response> callback) { if(APIHelpers.paramIsNull(userName, callback)) { return; } //include an empty json object to pass the parsing on airwolf. It doesn't like an empty string. JSONObject object = new JSONObject(); buildInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback, false).sendPasswordResetForParent(userName, object, callback); } /** * The API call to actually reset the parent's password to the one they just created. * * @param userName * @param password * @param callback */ public static void resetParentPassword(String userName, String password, CanvasCallback<ResetParent> callback) { if(APIHelpers.paramIsNull(userName, password, callback)) { return; } Parent parent = new Parent(); parent.setUsername(userName); parent.setPassword(password); buildInterface(UsersInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback, false).resetParentPassword(parent, callback); } ///////////////////////////////////////////////////////////////////////// // Synchronous Calls ///////////////////////////////////////////////////////////////////////// public static FileUploadParams getFileUploadParams(Context context, String fileName, long size, String contentType, Long parentFolderId){ return buildInterface(UsersInterface.class, context).getFileUploadParams(size, fileName, contentType, parentFolderId, ""); } public static FileUploadParams getFileUploadParams(Context context, String fileName, long size, String contentType, String parentFolderPath){ return buildInterface(UsersInterface.class, context).getFileUploadParams(size, fileName, contentType, parentFolderPath, ""); } public static Attachment uploadUserFile(String uploadUrl, LinkedHashMap<String,String> uploadParams, String mimeType, File file){ return buildUploadInterface(UsersInterface.class, uploadUrl).uploadUserFile(uploadParams, new TypedFile(mimeType, file)); } ///////////////////////////////////////////////////////////////////////// // Helpers ///////////////////////////////////////////////////////////////////////// private static String getEnrollmentTypeString(ENROLLMENT_TYPE enrollment_type){ String enrollmentType = ""; switch (enrollment_type){ case DESIGNER: enrollmentType = "designer"; break; case OBSERVER: enrollmentType = "observer"; break; case STUDENT: enrollmentType = "student"; break; case TA: enrollmentType = "ta"; break; case TEACHER: enrollmentType = "teacher"; break; } return enrollmentType; } }