use of org.odk.collect.forms.instances.Instance in project collect by opendatakit.
the class InstanceServerUploaderTask method doInBackground.
@Override
public Outcome doInBackground(Long... instanceIdsToUpload) {
Outcome outcome = new Outcome();
InstanceServerUploader uploader = new InstanceServerUploader(httpInterface, webCredentialsUtils, new HashMap<>(), settingsProvider.getUnprotectedSettings());
List<Instance> instancesToUpload = uploader.getInstancesFromIds(instanceIdsToUpload);
String deviceId = new PropertyManager().getSingularProperty(PropertyManager.PROPMGR_DEVICE_ID);
for (int i = 0; i < instancesToUpload.size(); i++) {
if (isCancelled()) {
return outcome;
}
Instance instance = instancesToUpload.get(i);
publishProgress(i + 1, instancesToUpload.size());
try {
String destinationUrl = uploader.getUrlToSubmitTo(instance, deviceId, completeDestinationUrl, null);
String customMessage = uploader.uploadOneSubmission(instance, destinationUrl);
outcome.messagesByInstanceId.put(instance.getDbId().toString(), customMessage != null ? customMessage : getLocalizedString(Collect.getInstance(), R.string.success));
analytics.logEvent(SUBMISSION, "HTTP", Collect.getFormIdentifierHash(instance.getFormId(), instance.getFormVersion()));
} catch (UploadAuthRequestedException e) {
outcome.authRequestingServer = e.getAuthRequestingServer();
// Don't add the instance that caused an auth request to the map because we want to
// retry. Items present in the map are considered already attempted and won't be
// retried.
} catch (UploadException e) {
outcome.messagesByInstanceId.put(instance.getDbId().toString(), e.getDisplayMessage());
}
}
return outcome;
}
use of org.odk.collect.forms.instances.Instance in project collect by opendatakit.
the class SaveFormToDisk method exportData.
/**
* Write's the data to the sdcard, and updates the instances content provider.
* In theory we don't have to write to disk, and this is where you'd add
* other methods.
*/
private void exportData(boolean markCompleted, FormSaver.ProgressListener progressListener) throws IOException, EncryptionException {
FormController formController = Collect.getInstance().getFormController();
progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_collecting_message));
ByteArrayPayload payload = formController.getFilledInFormXml();
// write out xml
String instancePath = formController.getInstanceFile().getAbsolutePath();
for (String fileName : tempFiles) {
mediaUtils.deleteMediaFile(fileName);
}
progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_saving_message));
writeFile(payload, instancePath);
// Write last-saved instance
String lastSavedPath = formController.getLastSavedPath();
writeFile(payload, lastSavedPath);
// update the uri. We have exported the reloadable instance, so update status...
// Since we saved a reloadable instance, it is flagged as re-openable so that if any error
// occurs during the packaging of the data for the server fails (e.g., encryption),
// we can still reopen the filled-out form and re-save it at a later time.
updateInstanceDatabase(true, true);
if (markCompleted) {
// now see if the packaging of the data for the server would make it
// non-reopenable (e.g., encryption or other fraction of the form).
boolean canEditAfterCompleted = formController.isSubmissionEntireForm();
boolean isEncrypted = false;
// build a submission.xml to hold the data being submitted
// and (if appropriate) encrypt the files on the side
// pay attention to the ref attribute of the submission profile...
File instanceXml = formController.getInstanceFile();
File submissionXml = new File(instanceXml.getParentFile(), "submission.xml");
payload = formController.getSubmissionXml();
// write out submission.xml -- the data to actually submit to aggregate
progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_finalizing_message));
writeFile(payload, submissionXml.getAbsolutePath());
// see if the form is encrypted and we can encrypt it...
EncryptedFormInformation formInfo = EncryptionUtils.getEncryptedFormInformation(uri, formController.getSubmissionMetadata());
if (formInfo != null) {
// if we are encrypting, the form cannot be reopened afterward
canEditAfterCompleted = false;
// and encrypt the submission (this is a one-way operation)...
progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_encrypting_message));
EncryptionUtils.generateEncryptedSubmission(instanceXml, submissionXml, formInfo);
isEncrypted = true;
analytics.logEvent(ENCRYPT_SUBMISSION, AnalyticsUtils.getFormHash(Collect.getInstance().getFormController()), "");
}
// At this point, we have:
// 1. the saved original instanceXml,
// 2. all the plaintext attachments
// 2. the submission.xml that is the completed xml (whether encrypting or not)
// 3. all the encrypted attachments if encrypting (isEncrypted = true).
//
// NEXT:
// 1. Update the instance database (with status complete).
// 2. Overwrite the instanceXml with the submission.xml
// and remove the plaintext attachments if encrypting
updateInstanceDatabase(false, canEditAfterCompleted);
if (!canEditAfterCompleted) {
manageFilesAfterSavingEncryptedForm(instanceXml, submissionXml);
} else {
// (we don't need to delete and rename anything).
if (!submissionXml.delete()) {
String msg = "Error deleting " + submissionXml.getAbsolutePath() + " (instance is re-openable)";
Timber.w(msg);
}
}
// (anything not named instanceXml or anything not ending in .enc)
if (isEncrypted) {
InstancesRepository instancesRepository = new InstancesRepositoryProvider(Collect.getInstance()).get();
Instance instance = instancesRepository.get(ContentUriHelper.getIdFromUri(uri));
// Clear the geometry. Done outside of updateInstanceDatabase to avoid multiple
// branches and because it has no knowledge of encryption status.
instancesRepository.save(new Instance.Builder(instance).geometry(null).geometryType(null).build());
ContentValues values = new ContentValues();
values.put(DatabaseInstanceColumns.GEOMETRY, (String) null);
values.put(DatabaseInstanceColumns.GEOMETRY_TYPE, (String) null);
if (!EncryptionUtils.deletePlaintextFiles(instanceXml, new File(lastSavedPath))) {
Timber.e("Error deleting plaintext files for %s", instanceXml.getAbsolutePath());
}
}
}
}
use of org.odk.collect.forms.instances.Instance in project collect by opendatakit.
the class InstanceUploader method submissionComplete.
public void submissionComplete(Instance instance, boolean successful) {
InstancesRepository instancesRepository = instancesRepositoryProvider.get();
if (successful) {
instancesRepository.save(new Instance.Builder(instance).status(Instance.STATUS_SUBMITTED).build());
} else {
instancesRepository.save(new Instance.Builder(instance).status(Instance.STATUS_SUBMISSION_FAILED).build());
}
instancesAppState.update();
}
use of org.odk.collect.forms.instances.Instance in project collect by opendatakit.
the class InstanceUploaderUtils method getUploadResultMessage.
/**
* Returns a formatted message including submission results for all the filled forms accessible
* through instancesProcessed in the following structure:
*
* Instance name 1 - result
*
* Instance name 2 - result
*/
public static String getUploadResultMessage(InstancesRepository instancesRepository, Context context, Map<String, String> result) {
Set<String> keys = result.keySet();
Iterator<String> it = keys.iterator();
StringBuilder message = new StringBuilder();
while (it.hasNext()) {
Instance instance = instancesRepository.get(Long.valueOf(it.next()));
message.append(getUploadResultMessageForInstances(instance, result));
}
if (message.length() == 0) {
message = new StringBuilder(context.getString(R.string.no_forms_uploaded));
}
return message.toString().trim();
}
use of org.odk.collect.forms.instances.Instance in project collect by opendatakit.
the class InstanceDiskSynchronizer method doInBackground.
public String doInBackground() {
int currentInstance = ++counter;
Timber.i("[%d] doInBackground begins!", currentInstance);
try {
List<String> instancePaths = new LinkedList<>();
File instancesPath = new File(storagePathProvider.getOdkDirPath(StorageSubdirectory.INSTANCES));
if (instancesPath.exists() && instancesPath.isDirectory()) {
File[] instanceFolders = instancesPath.listFiles();
if (instanceFolders == null || instanceFolders.length == 0) {
Timber.i("[%d] Empty instance folder. Stopping scan process.", currentInstance);
Timber.d("Instance scan completed");
return currentStatus;
}
// Build the list of potential path that we need to add to the content provider
for (File instanceDir : instanceFolders) {
File instanceFile = new File(instanceDir, instanceDir.getName() + ".xml");
if (!instanceFile.exists()) {
// Look for submission file that might have been manually copied from e.g. Briefcase
File submissionFile = new File(instanceDir, "submission.xml");
if (submissionFile.exists()) {
submissionFile.renameTo(instanceFile);
}
}
if (instanceFile.exists() && instanceFile.canRead()) {
instancePaths.add(instanceFile.getAbsolutePath());
} else {
Timber.i("[%d] Ignoring: %s", currentInstance, instanceDir.getAbsolutePath());
}
}
final boolean instanceSyncFlag = settingsProvider.getUnprotectedSettings().getBoolean(ProjectKeys.KEY_INSTANCE_SYNC);
int counter = 0;
for (String instancePath : instancePaths) {
if (instancesRepository.getOneByPath(instancePath) != null) {
// Skip instances that are already stored in repo
continue;
}
String instanceFormId = getFormIdFromInstance(instancePath);
// only process if we can find the id from the instance file
if (instanceFormId != null) {
try {
// TODO: optimize this by caching the previously found form definition
// TODO: optimize this by caching unavailable form definition to skip
List<Form> forms = new FormsRepositoryProvider(Collect.getInstance()).get().getAllByFormId(instanceFormId);
if (!forms.isEmpty()) {
Form form = forms.get(0);
String jrFormId = form.getFormId();
String jrVersion = form.getVersion();
String formName = form.getDisplayName();
String submissionUri = form.getSubmissionUri();
Instance instance = instancesRepository.save(new Instance.Builder().instanceFilePath(instancePath).submissionUri(submissionUri).displayName(formName).formId(jrFormId).formVersion(jrVersion).status(instanceSyncFlag ? Instance.STATUS_COMPLETE : Instance.STATUS_INCOMPLETE).canEditWhenComplete(true).build());
counter++;
encryptInstanceIfNeeded(form, instance);
}
} catch (IOException | EncryptionException e) {
Timber.w(e);
}
}
}
if (counter > 0) {
currentStatus += getLocalizedString(Collect.getInstance(), R.string.instance_scan_count, counter);
}
}
} finally {
Timber.i("[%d] doInBackground ends!", currentInstance);
}
return currentStatus;
}
Aggregations