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;
}
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));
}
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()));
}
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;
}
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;
}
Aggregations