package com.instructure.canvasapi.api.compatibility_synchronous;
import android.app.Activity;
import android.content.Context;
import android.net.http.AndroidHttpClient;
import com.google.gson.Gson;
import com.instructure.canvasapi.model.Attachment;
import com.instructure.canvasapi.model.Avatar;
import com.instructure.canvasapi.utilities.CanvasRestAdapter;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
/**
* Created by Josh Ruesch on 10/16/13.
*
* Copyright (c) 2014 Instructure. All rights reserved.
*/
public class UploadFileSynchronousAPI {
/**
* These methods are all GUARANTEED to be called on the UI thread.
*/
public interface UploadFilesErrorHandler {
public void onFileQuotaExceeded();
public void onUnexpectedError(Exception exception);
}
//wrapper classes for the avatar so we can let the view know what type of error (if any) happened
public static class AvatarError {
public static int NONE = 0;
public static int QUOTA_EXCEEDED = 1;
public static int UNKNOWN = 2;
}
public static class AvatarWrapper {
public int error;
public Avatar avatar;
public AvatarWrapper(){}
}
public static AvatarWrapper postAvatar(String imageName, long size, String contentType, String path, Context context) {
String url = String.format(Locale.US, "/api/v1/users/self/files?name=%s&size=%d&content_type=%s", imageName, size, contentType);
//set the parent folder
String parentFolder = "&parent_folder_path=profile+pictures";
url += parentFolder;
//don't overwrite
url += "&on_duplicate=rename";
APIHttpResponse response = HttpHelpers.httpPost(url, null, context);
try
{
/*{
"upload_url": "https://some-bucket.s3.amazonaws.com/",
"upload_params": {
"key": "/users/1234/files/profile_pic.jpg",
"acl": "private",
"Filename": "profile_pic.jpg",
"AWSAccessKeyId": "some_id",
"Policy": "some_opaque_string",
"Signature": "another_opaque_string",
"Content-Type": "image/jpeg"
}
}
*/
ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
JSONObject json = new JSONObject(response.responseBody);
//See if we've exceeded the quota.
if(json.has("message") && json.getString("message").equals("file size exceeds quota")){
//let the user know
AvatarWrapper avatarWrapper = new AvatarWrapper();
avatarWrapper.avatar = null;
avatarWrapper.error = AvatarError.QUOTA_EXCEEDED;
return avatarWrapper;
}
String uploadUrl = json.getString("upload_url");
JSONObject params = json.getJSONObject("upload_params");
Iterator<?> keys = params.keys();
//get all the keys
while(keys.hasNext()) {
// loop to get the dynamic key
String currentDynamicKey = (String)keys.next();
//TODO: what to do if the parameter isn't a string??
pairs.add(new BasicNameValuePair(currentDynamicKey , params.getString(currentDynamicKey)));
}
File file = new File(path);
String postResponse = UploadFileSynchronousAPI.uploadFile(file, uploadUrl, contentType, pairs, context);
JSONObject object = new JSONObject(postResponse);
String avatarUrl = object.getString("url");
//set up a new avatar to return
Avatar avatar = new Avatar();
avatar.setUrl(avatarUrl);
avatar.setDisplayName(object.getString("display_name"));
avatar.setType(object.getString("content-type"));
AvatarWrapper avatarWrapper = new AvatarWrapper();
avatarWrapper.avatar = avatar;
avatarWrapper.error = AvatarError.NONE;
return avatarWrapper;
}
catch(Exception E)
{
AvatarWrapper avatarWrapper = new AvatarWrapper();
avatarWrapper.avatar = null;
avatarWrapper.error = AvatarError.UNKNOWN;
return avatarWrapper;
}
}
public static String postBackDrop(String imageName, long size, String contentType, String path, Context context){
String url = String.format(Locale.US, "/api/v1/users/self/files?name=%s&size=%d&content_type=%s", imageName, size, contentType);
//set parent folder
String parentFolder = "&parent_folder_path=profile+pictures";
url += parentFolder;
//dont overwrite
url += "&on_duplicate=rename";
APIHttpResponse response = HttpHelpers.httpPost(url, null, context);
try{
ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
JSONObject json = new JSONObject(response.responseBody);
String uploadUrl = json.getString("upload_url");
JSONObject params = json.getJSONObject("upload_params");
Iterator<?> keys = params.keys();
while(keys.hasNext()){
String currenDynamicKey = (String)keys.next();
pairs.add(new BasicNameValuePair(currenDynamicKey, params.getString(currenDynamicKey)));
}
File file = new File(path);
String postResponse = UploadFileSynchronousAPI.uploadFile(file, uploadUrl, contentType, pairs, context);
JSONObject object = new JSONObject(postResponse);
return object.getString("url");
}catch(Exception E){
return null;
}
}
public static Attachment uploadSubmissionFile(long courseId, long assignmentId, String name, long size, String path, String contentType, Activity activity, UploadFilesErrorHandler uploadFilesErrorHandler){
String url = String.format(Locale.US, "/api/v1/courses/%d/assignments/%d/submissions/self/files?name=%s&size=%d&on_duplicate=rename", courseId, assignmentId, name, size);
return uploadFile(url, null, path, contentType, activity, uploadFilesErrorHandler);
}
public static Attachment uploadPersonalFile(String name, Long parentFolderID, String path, long size, String contentType, Activity activity, UploadFilesErrorHandler uploadFilesErrorHandler){
String url = String.format(Locale.US, "/api/v1/users/self/files?name=%s&size=%d&on_duplicate=rename",name, size);
return uploadFile(url, parentFolderID, path, contentType, activity, uploadFilesErrorHandler);
}
public static Attachment uploadCourseFile(long courseId, String name, Long parentFolderID, long size, String path, String contentType, Activity activity, UploadFilesErrorHandler uploadFilesErrorHandler){
String url = String.format(Locale.US, "/api/v1/courses/"+courseId+"/files?name=%s&size=%d&on_duplicate=rename",name, size);
return uploadFile(url, parentFolderID, path, contentType, activity, uploadFilesErrorHandler);
}
private static Attachment uploadFile(String url, Long parentFolderID, String path, String contentType, Activity activity, final UploadFilesErrorHandler uploadFilesErrorHandler) {
if(parentFolderID != null){
url += "&parent_folder_id="+parentFolderID;
}
APIHttpResponse response = HttpHelpers.httpPost(url, null, activity);
try
{
/*{
"upload_url": "https://some-bucket.s3.amazonaws.com/",
"upload_params": {
"key": "/users/1234/files/profile_pic.jpg",
"acl": "private",
"Filename": "profile_pic.jpg",
"AWSAccessKeyId": "some_id",
"Policy": "some_opaque_string",
"Signature": "another_opaque_string",
"Content-Type": "image/jpeg"
}
}
*/
ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
JSONObject json = new JSONObject(response.responseBody);
//See if we've exceeded the quota.
if(json.has("message") && json.getString("message").equals("file size exceeds quota")){
if(uploadFilesErrorHandler != null && activity != null){
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
uploadFilesErrorHandler.onFileQuotaExceeded();
}
});
}
return null;
}
String uploadUrl = json.getString("upload_url");
JSONObject params = json.getJSONObject("upload_params");
Iterator<?> keys = params.keys();
//get all the keys
while(keys.hasNext()) {
// loop to get the dynamic key
String currentDynamicKey = (String)keys.next();
//TODO: what to do if the parameter isn't a string??
pairs.add(new BasicNameValuePair(currentDynamicKey , params.getString(currentDynamicKey)));
}
File file = new File(path);
String postResponse = UploadFileSynchronousAPI.uploadFile(file, uploadUrl, contentType, pairs, activity);
//Do the JSON parsing.
Gson gson = CanvasRestAdapter.getGSONParser();
return gson.fromJson(postResponse,Attachment.class);
} catch (final Exception exception) {
if (uploadFilesErrorHandler != null && activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
uploadFilesErrorHandler.onUnexpectedError(exception);
}
});
}
return null;
}
}
public static boolean submitFiles(long courseId, long assignmentId, ArrayList<Attachment> attachments, Context context) {
String url = String.format(Locale.US, "/api/v1/courses/%d/assignments/%d/submissions", courseId, assignmentId);
ArrayList<BasicNameValuePair> postVars = new ArrayList<BasicNameValuePair>();
postVars.add(new BasicNameValuePair("submission[submission_type]", "online_upload"));
//takes an array of file_ids, this is how to add an array for post variables
for(int i = 0; i < attachments.size(); i++) {
postVars.add(new BasicNameValuePair("submission[file_ids][]", Long.toString(attachments.get(i).getId())));
}
APIHttpResponse response = HttpHelpers.httpPost(url, postVars, context);
try {
JSONObject json = new JSONObject(response.responseBody);
return json.has("id");
}
catch(Exception E) {
return false;
}
}
//needs to be AndroidHttpClient to work for some reason. Not really clear why.
private static AndroidHttpClient mHttpClient;
//STEPS 2 AND 3 OF API
public static String uploadFile(File image, String url, String contentType, ArrayList<BasicNameValuePair> pairs, Context context) {
try {
//STEP 2 of API
HttpPost httppost = new HttpPost(url);
MultipartEntity multipartEntity = new MultipartEntity();
for(BasicNameValuePair pair : pairs) {
String value = pair.getValue();
multipartEntity.addPart(pair.getName(), new StringBody(pair.getValue()));
}
multipartEntity.addPart("file", new FileBody(image));
httppost.setEntity(multipartEntity);
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
if(mHttpClient == null) {
mHttpClient = AndroidHttpClient.newInstance("agent");
mHttpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
mHttpClient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
}
HttpResponse httpResponse = mHttpClient.execute(httppost);
String response = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
//STEP 3 of API
Header[] headerLocation = httpResponse.getHeaders("Location");
if(headerLocation.length <= 0) {
return "Header error";
}
String location = headerLocation[0].getValue();
Header[] headerContent = httpResponse.getHeaders("Content-Length");
if(headerContent.length <= 0) {
return "Header content error";
}
BasicNameValuePair pair = new BasicNameValuePair(headerContent[0].getName(), headerContent[0].getValue());
ArrayList<BasicNameValuePair> paramPairs = new ArrayList<BasicNameValuePair>();
pairs.add(pair);
APIHttpResponse postResponse = HttpHelpers.httpPost(location, paramPairs, context);
return postResponse.responseBody;
} catch (Exception e) {
return null;
}
}
}