|
|
|
@ -5,18 +5,13 @@
|
|
|
|
|
*/
|
|
|
|
|
package com.todoroo.astrid.actfm.sync;
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.LinkedList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
|
|
|
|
import org.apache.http.entity.mime.MultipartEntity;
|
|
|
|
|
import org.apache.http.entity.mime.content.FileBody;
|
|
|
|
|
import org.json.JSONArray;
|
|
|
|
|
import org.json.JSONException;
|
|
|
|
|
import org.json.JSONObject;
|
|
|
|
@ -26,11 +21,8 @@ import android.text.TextUtils;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import com.timsu.astrid.GCMIntentService;
|
|
|
|
|
import com.todoroo.andlib.data.TodorooCursor;
|
|
|
|
|
import com.todoroo.andlib.service.Autowired;
|
|
|
|
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
|
|
|
|
import com.todoroo.andlib.sql.Criterion;
|
|
|
|
|
import com.todoroo.andlib.sql.Query;
|
|
|
|
|
import com.todoroo.andlib.utility.AndroidUtilities;
|
|
|
|
|
import com.todoroo.andlib.utility.Preferences;
|
|
|
|
|
import com.todoroo.astrid.billing.BillingConstants;
|
|
|
|
@ -38,13 +30,9 @@ import com.todoroo.astrid.dao.MetadataDao;
|
|
|
|
|
import com.todoroo.astrid.dao.TagDataDao;
|
|
|
|
|
import com.todoroo.astrid.dao.TaskDao;
|
|
|
|
|
import com.todoroo.astrid.dao.UserDao;
|
|
|
|
|
import com.todoroo.astrid.data.Metadata;
|
|
|
|
|
import com.todoroo.astrid.data.MetadataApiDao.MetadataCriteria;
|
|
|
|
|
import com.todoroo.astrid.data.RemoteModel;
|
|
|
|
|
import com.todoroo.astrid.data.TagData;
|
|
|
|
|
import com.todoroo.astrid.data.Task;
|
|
|
|
|
import com.todoroo.astrid.data.User;
|
|
|
|
|
import com.todoroo.astrid.files.FileMetadata;
|
|
|
|
|
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
|
|
|
|
|
import com.todoroo.astrid.service.MetadataService;
|
|
|
|
|
import com.todoroo.astrid.service.TagDataService;
|
|
|
|
@ -290,99 +278,99 @@ public final class ActFmSyncService {
|
|
|
|
|
handleException("fetch-tag-order-io", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void pushAttachmentInBackground(final Metadata fileMetadata) {
|
|
|
|
|
if (!ActFmPreferenceService.isPremiumUser())
|
|
|
|
|
return;
|
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
waitUntilEmpty.close();
|
|
|
|
|
taskPushThreads.incrementAndGet();
|
|
|
|
|
try {
|
|
|
|
|
Task t = taskDao.fetch(fileMetadata.getValue(Metadata.TASK), Task.UUID);
|
|
|
|
|
if (t == null || !RemoteModel.isValidUuid(t.getUuid()))
|
|
|
|
|
return;
|
|
|
|
|
if (fileMetadata.getValue(FileMetadata.DELETION_DATE) > 0)
|
|
|
|
|
deleteAttachment(fileMetadata);
|
|
|
|
|
else
|
|
|
|
|
pushAttachment(t.getValue(Task.UUID), fileMetadata);
|
|
|
|
|
} finally {
|
|
|
|
|
if (taskPushThreads.decrementAndGet() == 0) {
|
|
|
|
|
waitUntilEmpty.open();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}).start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Push a file attachment to the server
|
|
|
|
|
* @param remoteTaskId
|
|
|
|
|
* @param fileMetadata
|
|
|
|
|
*/
|
|
|
|
|
public void pushAttachment(String remoteTaskId, Metadata fileMetadata) {
|
|
|
|
|
if (!ActFmPreferenceService.isPremiumUser())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!fileMetadata.containsNonNullValue(FileMetadata.FILE_PATH) || !RemoteModel.isValidUuid(remoteTaskId))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
File f = new File(fileMetadata.getValue(FileMetadata.FILE_PATH));
|
|
|
|
|
if (!f.exists())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!checkForToken())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ArrayList<Object> params = new ArrayList<Object>();
|
|
|
|
|
params.add("task_id"); params.add(remoteTaskId);
|
|
|
|
|
params.add("token"); params.add(token);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
MultipartEntity entity = new MultipartEntity();
|
|
|
|
|
FileBody body = new FileBody(f, fileMetadata.getValue(FileMetadata.FILE_TYPE));
|
|
|
|
|
entity.addPart("file", body);
|
|
|
|
|
|
|
|
|
|
JSONObject result = actFmInvoker.post("task_attachment_create", entity,
|
|
|
|
|
params.toArray(new Object[params.size()]));
|
|
|
|
|
|
|
|
|
|
fileMetadata.setValue(FileMetadata.REMOTE_ID, result.optLong("id"));
|
|
|
|
|
fileMetadata.setValue(FileMetadata.URL, result.optString("url"));
|
|
|
|
|
metadataService.save(fileMetadata);
|
|
|
|
|
} catch (ActFmServiceException e) {
|
|
|
|
|
handleException("push-attachment-error", e);
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
handleException("push-attachment-error", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void deleteAttachment(Metadata fileMetadata) {
|
|
|
|
|
long attachmentId = fileMetadata.getValue(FileMetadata.REMOTE_ID);
|
|
|
|
|
if (attachmentId <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!checkForToken())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ArrayList<Object> params = new ArrayList<Object>();
|
|
|
|
|
params.add("id"); params.add(attachmentId);
|
|
|
|
|
params.add("token"); params.add(token);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
JSONObject result = actFmInvoker.post("task_attachment_remove", null, params.toArray(new Object[params.size()]));
|
|
|
|
|
if (result.optString("status").equals("success")) {
|
|
|
|
|
metadataService.delete(fileMetadata);
|
|
|
|
|
}
|
|
|
|
|
} catch (ActFmServiceException e) {
|
|
|
|
|
if (e.result != null && e.result.optString("code").equals("not_found"))
|
|
|
|
|
metadataService.delete(fileMetadata);
|
|
|
|
|
else
|
|
|
|
|
handleException("push-attachment-error", e);
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
handleException("push-attachment-error", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
// public void pushAttachmentInBackground(final Metadata fileMetadata) {
|
|
|
|
|
// if (!ActFmPreferenceService.isPremiumUser())
|
|
|
|
|
// return;
|
|
|
|
|
// new Thread(new Runnable() {
|
|
|
|
|
// @Override
|
|
|
|
|
// public void run() {
|
|
|
|
|
// waitUntilEmpty.close();
|
|
|
|
|
// taskPushThreads.incrementAndGet();
|
|
|
|
|
// try {
|
|
|
|
|
// Task t = taskDao.fetch(fileMetadata.getValue(Metadata.TASK), Task.UUID);
|
|
|
|
|
// if (t == null || !RemoteModel.isValidUuid(t.getUuid()))
|
|
|
|
|
// return;
|
|
|
|
|
// if (fileMetadata.getValue(FileMetadata.DELETION_DATE) > 0)
|
|
|
|
|
// deleteAttachment(fileMetadata);
|
|
|
|
|
// else
|
|
|
|
|
// pushAttachment(t.getValue(Task.UUID), fileMetadata);
|
|
|
|
|
// } finally {
|
|
|
|
|
// if (taskPushThreads.decrementAndGet() == 0) {
|
|
|
|
|
// waitUntilEmpty.open();
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }).start();
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * Push a file attachment to the server
|
|
|
|
|
// * @param remoteTaskId
|
|
|
|
|
// * @param fileMetadata
|
|
|
|
|
// */
|
|
|
|
|
// public void pushAttachment(String remoteTaskId, Metadata fileMetadata) {
|
|
|
|
|
// if (!ActFmPreferenceService.isPremiumUser())
|
|
|
|
|
// return;
|
|
|
|
|
//
|
|
|
|
|
// if (!fileMetadata.containsNonNullValue(FileMetadata.FILE_PATH) || !RemoteModel.isValidUuid(remoteTaskId))
|
|
|
|
|
// return;
|
|
|
|
|
//
|
|
|
|
|
// File f = new File(fileMetadata.getValue(FileMetadata.FILE_PATH));
|
|
|
|
|
// if (!f.exists())
|
|
|
|
|
// return;
|
|
|
|
|
//
|
|
|
|
|
// if (!checkForToken())
|
|
|
|
|
// return;
|
|
|
|
|
//
|
|
|
|
|
// ArrayList<Object> params = new ArrayList<Object>();
|
|
|
|
|
// params.add("task_id"); params.add(remoteTaskId);
|
|
|
|
|
// params.add("token"); params.add(token);
|
|
|
|
|
//
|
|
|
|
|
// try {
|
|
|
|
|
// MultipartEntity entity = new MultipartEntity();
|
|
|
|
|
// FileBody body = new FileBody(f, fileMetadata.getValue(FileMetadata.FILE_TYPE));
|
|
|
|
|
// entity.addPart("file", body);
|
|
|
|
|
//
|
|
|
|
|
// JSONObject result = actFmInvoker.post("task_attachment_create", entity,
|
|
|
|
|
// params.toArray(new Object[params.size()]));
|
|
|
|
|
//
|
|
|
|
|
// fileMetadata.setValue(FileMetadata.REMOTE_ID, result.optLong("id"));
|
|
|
|
|
// fileMetadata.setValue(FileMetadata.URL, result.optString("url"));
|
|
|
|
|
// metadataService.save(fileMetadata);
|
|
|
|
|
// } catch (ActFmServiceException e) {
|
|
|
|
|
// handleException("push-attachment-error", e);
|
|
|
|
|
// } catch (IOException e) {
|
|
|
|
|
// handleException("push-attachment-error", e);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// public void deleteAttachment(Metadata fileMetadata) {
|
|
|
|
|
// long attachmentId = fileMetadata.getValue(FileMetadata.REMOTE_ID);
|
|
|
|
|
// if (attachmentId <= 0)
|
|
|
|
|
// return;
|
|
|
|
|
//
|
|
|
|
|
// if (!checkForToken())
|
|
|
|
|
// return;
|
|
|
|
|
//
|
|
|
|
|
// ArrayList<Object> params = new ArrayList<Object>();
|
|
|
|
|
// params.add("id"); params.add(attachmentId);
|
|
|
|
|
// params.add("token"); params.add(token);
|
|
|
|
|
//
|
|
|
|
|
// try {
|
|
|
|
|
// JSONObject result = actFmInvoker.post("task_attachment_remove", null, params.toArray(new Object[params.size()]));
|
|
|
|
|
// if (result.optString("status").equals("success")) {
|
|
|
|
|
// metadataService.delete(fileMetadata);
|
|
|
|
|
// }
|
|
|
|
|
// } catch (ActFmServiceException e) {
|
|
|
|
|
// if (e.result != null && e.result.optString("code").equals("not_found"))
|
|
|
|
|
// metadataService.delete(fileMetadata);
|
|
|
|
|
// else
|
|
|
|
|
// handleException("push-attachment-error", e);
|
|
|
|
|
// } catch (IOException e) {
|
|
|
|
|
// handleException("push-attachment-error", e);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// --- data fetch methods
|
|
|
|
|
public int fetchFeaturedLists(int serverTime) throws JSONException, IOException {
|
|
|
|
@ -477,64 +465,64 @@ public final class ActFmSyncService {
|
|
|
|
|
parameters[i+2] = getParameters[i];
|
|
|
|
|
return actFmInvoker.invoke(method, parameters);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- helpers
|
|
|
|
|
private void synchronizeAttachments(JSONObject item, Task model) {
|
|
|
|
|
TodorooCursor<Metadata> attachments = metadataService.query(Query.select(Metadata.PROPERTIES)
|
|
|
|
|
.where(Criterion.and(MetadataCriteria.byTaskAndwithKey(model.getId(),
|
|
|
|
|
FileMetadata.METADATA_KEY), FileMetadata.REMOTE_ID.gt(0))));
|
|
|
|
|
try {
|
|
|
|
|
HashMap<Long, Metadata> currentFiles = new HashMap<Long, Metadata>();
|
|
|
|
|
for (attachments.moveToFirst(); !attachments.isAfterLast(); attachments.moveToNext()) {
|
|
|
|
|
Metadata m = new Metadata(attachments);
|
|
|
|
|
currentFiles.put(m.getValue(FileMetadata.REMOTE_ID), m);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSONArray remoteFiles = item.getJSONArray("attachments");
|
|
|
|
|
for (int i = 0; i < remoteFiles.length(); i++) {
|
|
|
|
|
JSONObject file = remoteFiles.getJSONObject(i);
|
|
|
|
|
|
|
|
|
|
long id = file.optLong("id");
|
|
|
|
|
if (currentFiles.containsKey(id)) {
|
|
|
|
|
// Match, make sure name and url are up to date, then remove from map
|
|
|
|
|
Metadata fileMetadata = currentFiles.get(id);
|
|
|
|
|
fileMetadata.setValue(FileMetadata.URL, file.getString("url"));
|
|
|
|
|
fileMetadata.setValue(FileMetadata.NAME, file.getString("name"));
|
|
|
|
|
metadataService.save(fileMetadata);
|
|
|
|
|
currentFiles.remove(id);
|
|
|
|
|
} else {
|
|
|
|
|
// Create new file attachment
|
|
|
|
|
Metadata newAttachment = FileMetadata.createNewFileMetadata(model.getId(), "",
|
|
|
|
|
file.getString("name"), file.getString("content_type"));
|
|
|
|
|
String url = file.getString("url");
|
|
|
|
|
newAttachment.setValue(FileMetadata.URL, url);
|
|
|
|
|
newAttachment.setValue(FileMetadata.REMOTE_ID, id);
|
|
|
|
|
metadataService.save(newAttachment);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove all the leftovers
|
|
|
|
|
Set<Long> attachmentsToDelete = currentFiles.keySet();
|
|
|
|
|
for (Long remoteId : attachmentsToDelete) {
|
|
|
|
|
Metadata toDelete = currentFiles.get(remoteId);
|
|
|
|
|
String path = toDelete.getValue(FileMetadata.FILE_PATH);
|
|
|
|
|
if (TextUtils.isEmpty(path))
|
|
|
|
|
metadataService.delete(toDelete);
|
|
|
|
|
else {
|
|
|
|
|
File f = new File(toDelete.getValue(FileMetadata.FILE_PATH));
|
|
|
|
|
if (!f.exists() || f.delete()) {
|
|
|
|
|
metadataService.delete(toDelete);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (JSONException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
} finally {
|
|
|
|
|
attachments.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
// // --- helpers
|
|
|
|
|
// private void synchronizeAttachments(JSONObject item, Task model) {
|
|
|
|
|
// TodorooCursor<Metadata> attachments = metadataService.query(Query.select(Metadata.PROPERTIES)
|
|
|
|
|
// .where(Criterion.and(MetadataCriteria.byTaskAndwithKey(model.getId(),
|
|
|
|
|
// FileMetadata.METADATA_KEY), FileMetadata.REMOTE_ID.gt(0))));
|
|
|
|
|
// try {
|
|
|
|
|
// HashMap<Long, Metadata> currentFiles = new HashMap<Long, Metadata>();
|
|
|
|
|
// for (attachments.moveToFirst(); !attachments.isAfterLast(); attachments.moveToNext()) {
|
|
|
|
|
// Metadata m = new Metadata(attachments);
|
|
|
|
|
// currentFiles.put(m.getValue(FileMetadata.REMOTE_ID), m);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// JSONArray remoteFiles = item.getJSONArray("attachments");
|
|
|
|
|
// for (int i = 0; i < remoteFiles.length(); i++) {
|
|
|
|
|
// JSONObject file = remoteFiles.getJSONObject(i);
|
|
|
|
|
//
|
|
|
|
|
// long id = file.optLong("id");
|
|
|
|
|
// if (currentFiles.containsKey(id)) {
|
|
|
|
|
// // Match, make sure name and url are up to date, then remove from map
|
|
|
|
|
// Metadata fileMetadata = currentFiles.get(id);
|
|
|
|
|
// fileMetadata.setValue(FileMetadata.URL, file.getString("url"));
|
|
|
|
|
// fileMetadata.setValue(FileMetadata.NAME, file.getString("name"));
|
|
|
|
|
// metadataService.save(fileMetadata);
|
|
|
|
|
// currentFiles.remove(id);
|
|
|
|
|
// } else {
|
|
|
|
|
// // Create new file attachment
|
|
|
|
|
// Metadata newAttachment = FileMetadata.createNewFileMetadata(model.getId(), "",
|
|
|
|
|
// file.getString("name"), file.getString("content_type"));
|
|
|
|
|
// String url = file.getString("url");
|
|
|
|
|
// newAttachment.setValue(FileMetadata.URL, url);
|
|
|
|
|
// newAttachment.setValue(FileMetadata.REMOTE_ID, id);
|
|
|
|
|
// metadataService.save(newAttachment);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// // Remove all the leftovers
|
|
|
|
|
// Set<Long> attachmentsToDelete = currentFiles.keySet();
|
|
|
|
|
// for (Long remoteId : attachmentsToDelete) {
|
|
|
|
|
// Metadata toDelete = currentFiles.get(remoteId);
|
|
|
|
|
// String path = toDelete.getValue(FileMetadata.FILE_PATH);
|
|
|
|
|
// if (TextUtils.isEmpty(path))
|
|
|
|
|
// metadataService.delete(toDelete);
|
|
|
|
|
// else {
|
|
|
|
|
// File f = new File(toDelete.getValue(FileMetadata.FILE_PATH));
|
|
|
|
|
// if (!f.exists() || f.delete()) {
|
|
|
|
|
// metadataService.delete(toDelete);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// } catch (JSONException e) {
|
|
|
|
|
// e.printStackTrace();
|
|
|
|
|
// } finally {
|
|
|
|
|
// attachments.close();
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void handleException(String message, Exception exception) {
|
|
|
|
|