Search in sources :

Example 1 with FormsRepositoryProvider

use of org.odk.collect.android.utilities.FormsRepositoryProvider 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)

Example 2 with FormsRepositoryProvider

use of org.odk.collect.android.utilities.FormsRepositoryProvider in project collect by opendatakit.

the class InstanceSubmitter method submitInstances.

public Pair<Boolean, String> submitInstances(List<Instance> toUpload) throws SubmitException {
    if (toUpload.isEmpty()) {
        throw new SubmitException(Type.NOTHING_TO_SUBMIT);
    }
    String protocol = generalSettings.getString(ProjectKeys.KEY_PROTOCOL);
    InstanceUploader uploader;
    Map<String, String> resultMessagesByInstanceId = new HashMap<>();
    String deviceId = null;
    boolean anyFailure = false;
    if (protocol.equals(ProjectKeys.PROTOCOL_GOOGLE_SHEETS)) {
        if (permissionsProvider.isGetAccountsPermissionGranted()) {
            String googleUsername = googleAccountsManager.getLastSelectedAccountIfValid();
            if (googleUsername.isEmpty()) {
                throw new SubmitException(Type.GOOGLE_ACCOUNT_NOT_SET);
            }
            googleAccountsManager.selectAccount(googleUsername);
            uploader = new InstanceGoogleSheetsUploader(googleApiProvider.getDriveApi(googleUsername), googleApiProvider.getSheetsApi(googleUsername));
        } else {
            throw new SubmitException(Type.GOOGLE_ACCOUNT_NOT_PERMITTED);
        }
    } else {
        OpenRosaHttpInterface httpInterface = Collect.getInstance().getComponent().openRosaHttpInterface();
        uploader = new InstanceServerUploader(httpInterface, new WebCredentialsUtils(generalSettings), new HashMap<>(), generalSettings);
        deviceId = new PropertyManager().getSingularProperty(PropertyManager.PROPMGR_DEVICE_ID);
    }
    for (Instance instance : toUpload) {
        try {
            String destinationUrl;
            if (protocol.equals(ProjectKeys.PROTOCOL_GOOGLE_SHEETS)) {
                destinationUrl = uploader.getUrlToSubmitTo(instance, null, null, generalSettings.getString(KEY_GOOGLE_SHEETS_URL));
                if (!InstanceUploaderUtils.doesUrlRefersToGoogleSheetsFile(destinationUrl)) {
                    anyFailure = true;
                    resultMessagesByInstanceId.put(instance.getDbId().toString(), SPREADSHEET_UPLOADED_TO_GOOGLE_DRIVE);
                    continue;
                }
            } else {
                destinationUrl = uploader.getUrlToSubmitTo(instance, deviceId, null, null);
            }
            String customMessage = uploader.uploadOneSubmission(instance, destinationUrl);
            resultMessagesByInstanceId.put(instance.getDbId().toString(), customMessage != null ? customMessage : getLocalizedString(Collect.getInstance(), R.string.success));
            // communicated to the user. Maybe successful delete should also be communicated?
            if (InstanceUploaderUtils.shouldFormBeDeleted(formsRepository, instance.getFormId(), instance.getFormVersion(), generalSettings.getBoolean(ProjectKeys.KEY_DELETE_AFTER_SEND))) {
                new InstanceDeleter(new InstancesRepositoryProvider(Collect.getInstance()).get(), new FormsRepositoryProvider(Collect.getInstance()).get()).delete(instance.getDbId());
            }
            String action = protocol.equals(ProjectKeys.PROTOCOL_GOOGLE_SHEETS) ? "HTTP-Sheets auto" : "HTTP auto";
            String label = Collect.getFormIdentifierHash(instance.getFormId(), instance.getFormVersion());
            analytics.logEvent(SUBMISSION, action, label);
        } catch (UploadException e) {
            Timber.d(e);
            anyFailure = true;
            resultMessagesByInstanceId.put(instance.getDbId().toString(), e.getDisplayMessage());
        }
    }
    return new Pair<>(anyFailure, InstanceUploaderUtils.getUploadResultMessage(instancesRepository, Collect.getInstance(), resultMessagesByInstanceId));
}
Also used : InstanceServerUploader(org.odk.collect.android.upload.InstanceServerUploader) InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) HashMap(java.util.HashMap) 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) FormsRepositoryProvider(org.odk.collect.android.utilities.FormsRepositoryProvider) InstanceUploader(org.odk.collect.android.upload.InstanceUploader) OpenRosaHttpInterface(org.odk.collect.android.openrosa.OpenRosaHttpInterface) InstanceGoogleSheetsUploader(org.odk.collect.android.gdrive.InstanceGoogleSheetsUploader) WebCredentialsUtils(org.odk.collect.android.utilities.WebCredentialsUtils) Pair(android.util.Pair)

Example 3 with FormsRepositoryProvider

use of org.odk.collect.android.utilities.FormsRepositoryProvider in project collect by opendatakit.

the class Collect method getFormIdentifierHash.

/**
 * Gets a unique, privacy-preserving identifier for a form based on its id and version.
 *
 * @param formId      id of a form
 * @param formVersion version of a form
 * @return md5 hash of the form title, a space, the form ID
 */
public static String getFormIdentifierHash(String formId, String formVersion) {
    Form form = new FormsRepositoryProvider(Collect.getInstance()).get().getLatestByFormIdAndVersion(formId, formVersion);
    String formTitle = form != null ? form.getDisplayName() : "";
    String formIdentifier = formTitle + " " + formId;
    return Md5.getMd5Hash(new ByteArrayInputStream(formIdentifier.getBytes()));
}
Also used : Form(org.odk.collect.forms.Form) ByteArrayInputStream(java.io.ByteArrayInputStream) FormsRepositoryProvider(org.odk.collect.android.utilities.FormsRepositoryProvider)

Example 4 with FormsRepositoryProvider

use of org.odk.collect.android.utilities.FormsRepositoryProvider in project collect by opendatakit.

the class InstanceListCursorAdapter method getView.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = super.getView(position, convertView, parent);
    ImageView imageView = view.findViewById(R.id.image);
    setImageFromStatus(imageView);
    setUpSubtext(view);
    // Update: This only seems to be the case in Edit Saved Forms and it's not clear why...
    if (!shouldCheckDisabled) {
        return view;
    }
    boolean formExists = false;
    boolean isFormEncrypted = false;
    String formId = getCursor().getString(getCursor().getColumnIndex(DatabaseInstanceColumns.JR_FORM_ID));
    String formVersion = getCursor().getString(getCursor().getColumnIndex(DatabaseInstanceColumns.JR_VERSION));
    Form form = new FormsRepositoryProvider(context.getApplicationContext()).get().getLatestByFormIdAndVersion(formId, formVersion);
    if (form != null) {
        String base64RSAPublicKey = form.getBASE64RSAPublicKey();
        formExists = true;
        isFormEncrypted = base64RSAPublicKey != null;
    }
    long date = getCursor().getLong(getCursor().getColumnIndex(DatabaseInstanceColumns.DELETED_DATE));
    if (date != 0 || !formExists || isFormEncrypted) {
        String disabledMessage;
        if (date != 0) {
            try {
                String deletedTime = context.getString(R.string.deleted_on_date_at_time);
                disabledMessage = new SimpleDateFormat(deletedTime, Locale.getDefault()).format(new Date(date));
            } catch (IllegalArgumentException e) {
                Timber.e(e);
                disabledMessage = context.getString(R.string.submission_deleted);
            }
        } else if (!formExists) {
            disabledMessage = context.getString(R.string.deleted_form);
        } else {
            disabledMessage = context.getString(R.string.encrypted_form);
        }
        setDisabled(view, disabledMessage);
    } else {
        setEnabled(view);
    }
    return view;
}
Also used : Form(org.odk.collect.forms.Form) ImageView(android.widget.ImageView) FormsRepositoryProvider(org.odk.collect.android.utilities.FormsRepositoryProvider) ImageView(android.widget.ImageView) TextView(android.widget.TextView) View(android.view.View) SimpleDateFormat(java.text.SimpleDateFormat) Date(java.util.Date)

Example 5 with FormsRepositoryProvider

use of org.odk.collect.android.utilities.FormsRepositoryProvider in project collect by opendatakit.

the class InstanceGoogleSheetsUploader method uploadOneSubmission.

@Override
public String uploadOneSubmission(Instance instance, String spreadsheetUrl) throws UploadException {
    File instanceFile = new File(instance.getInstanceFilePath());
    if (!instanceFile.exists()) {
        throw new UploadException(FAIL + "instance XML file does not exist!");
    }
    // Get corresponding blank form and verify there is exactly 1
    List<Form> forms = new FormsRepositoryProvider(Collect.getInstance()).get().getAllByFormIdAndVersion(instance.getFormId(), instance.getFormVersion());
    try {
        if (forms.size() != 1) {
            throw new UploadException(getLocalizedString(Collect.getInstance(), R.string.not_exactly_one_blank_form_for_this_form_id));
        }
        Form form = forms.get(0);
        if (form.getBASE64RSAPublicKey() != null) {
            submissionComplete(instance, false);
            throw new UploadException(getLocalizedString(Collect.getInstance(), R.string.google_sheets_encrypted_message));
        }
        String formFilePath = PathUtils.getAbsoluteFilePath(new StoragePathProvider().getOdkDirPath(StorageSubdirectory.FORMS), form.getFormFilePath());
        TreeElement instanceElement = getInstanceElement(formFilePath, instanceFile);
        setUpSpreadsheet(spreadsheetUrl);
        sheetsHelper.updateSpreadsheetLocaleForNewSpreadsheet(spreadsheet.getSpreadsheetId(), spreadsheet.getSheets().get(0).getProperties().getTitle());
        if (hasRepeatableGroups(instanceElement)) {
            createSheetsIfNeeded(instanceElement);
        }
        String key = getInstanceID(getChildElements(instanceElement, false));
        if (key == null) {
            key = PropertyUtils.genUUID();
        }
        insertRows(instance, instanceElement, null, key, instanceFile, spreadsheet.getSheets().get(0).getProperties().getTitle());
    } catch (UploadException e) {
        submissionComplete(instance, false);
        throw e;
    } catch (GoogleJsonResponseException e) {
        submissionComplete(instance, false);
        throw new UploadException(getErrorMessageFromGoogleJsonResponseException(e));
    }
    submissionComplete(instance, true);
    // Google Sheets can't provide a custom success message
    return null;
}
Also used : GoogleJsonResponseException(com.google.api.client.googleapis.json.GoogleJsonResponseException) StoragePathProvider(org.odk.collect.android.storage.StoragePathProvider) Form(org.odk.collect.forms.Form) UploadException(org.odk.collect.android.upload.UploadException) FormsRepositoryProvider(org.odk.collect.android.utilities.FormsRepositoryProvider) LocalizedApplicationKt.getLocalizedString(org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString) File(java.io.File) TreeElement(org.javarosa.core.model.instance.TreeElement) AbstractTreeElement(org.javarosa.core.model.instance.AbstractTreeElement)

Aggregations

FormsRepositoryProvider (org.odk.collect.android.utilities.FormsRepositoryProvider)7 Form (org.odk.collect.forms.Form)6 LocalizedApplicationKt.getLocalizedString (org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString)5 Instance (org.odk.collect.forms.instances.Instance)4 UploadException (org.odk.collect.android.upload.UploadException)3 File (java.io.File)2 InstancesRepositoryProvider (org.odk.collect.android.utilities.InstancesRepositoryProvider)2 Pair (android.util.Pair)1 View (android.view.View)1 ImageView (android.widget.ImageView)1 TextView (android.widget.TextView)1 GoogleJsonResponseException (com.google.api.client.googleapis.json.GoogleJsonResponseException)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 SimpleDateFormat (java.text.SimpleDateFormat)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 LinkedList (java.util.LinkedList)1 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)1 FormInstance (org.javarosa.core.model.instance.FormInstance)1