Search in sources :

Example 6 with Instance

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;
}
Also used : InstanceServerUploader(org.odk.collect.android.upload.InstanceServerUploader) Instance(org.odk.collect.forms.instances.Instance) PropertyManager(org.odk.collect.android.logic.PropertyManager) UploadException(org.odk.collect.android.upload.UploadException) LocalizedApplicationKt.getLocalizedString(org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString) UploadAuthRequestedException(org.odk.collect.android.upload.UploadAuthRequestedException)

Example 7 with Instance

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());
            }
        }
    }
}
Also used : FormController(org.odk.collect.android.javarosawrapper.FormController) ContentValues(android.content.ContentValues) InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) ByteArrayPayload(org.javarosa.core.services.transport.payload.ByteArrayPayload) FormInstance(org.javarosa.core.model.instance.FormInstance) Instance(org.odk.collect.forms.instances.Instance) InstancesRepository(org.odk.collect.forms.instances.InstancesRepository) LocalizedApplicationKt.getLocalizedString(org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString) EncryptedFormInformation(org.odk.collect.android.utilities.EncryptionUtils.EncryptedFormInformation) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File)

Example 8 with Instance

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();
}
Also used : Instance(org.odk.collect.forms.instances.Instance) InstancesRepository(org.odk.collect.forms.instances.InstancesRepository)

Example 9 with Instance

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();
}
Also used : Instance(org.odk.collect.forms.instances.Instance) LocalizedApplicationKt.getLocalizedString(org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString)

Example 10 with Instance

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;
}
Also used : Form(org.odk.collect.forms.Form) Instance(org.odk.collect.forms.instances.Instance) LocalizedApplicationKt.getLocalizedString(org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString) FormsRepositoryProvider(org.odk.collect.android.utilities.FormsRepositoryProvider) IOException(java.io.IOException) LinkedList(java.util.LinkedList) EncryptionException(org.odk.collect.android.exception.EncryptionException) File(java.io.File)

Aggregations

Instance (org.odk.collect.forms.instances.Instance)62 Test (org.junit.Test)28 InstancesRepository (org.odk.collect.forms.instances.InstancesRepository)23 InstancesRepositoryProvider (org.odk.collect.android.utilities.InstancesRepositoryProvider)10 LocalizedApplicationKt.getLocalizedString (org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString)9 File (java.io.File)7 DatabaseObjectMapper.getValuesFromInstance (org.odk.collect.android.database.DatabaseObjectMapper.getValuesFromInstance)7 Uri (android.net.Uri)6 Form (org.odk.collect.forms.Form)6 InstanceUtils.buildInstance (org.odk.collect.formstest.InstanceUtils.buildInstance)6 Pair (android.util.Pair)5 ArrayList (java.util.ArrayList)5 FormsRepositoryProvider (org.odk.collect.android.utilities.FormsRepositoryProvider)5 Date (java.util.Date)4 FormController (org.odk.collect.android.javarosawrapper.FormController)4 MapPoint (org.odk.collect.geo.maps.MapPoint)4 ContentValues (android.content.ContentValues)3 Intent (android.content.Intent)3 Cursor (android.database.Cursor)3 AsyncTask (android.os.AsyncTask)2