use of org.sagebionetworks.bridge.upload.UploadValidationException in project BridgeServer2 by Sage-Bionetworks.
the class HealthDataService method submitHealthData.
/* HEALTH DATA SUBMISSION */
/**
* Synchronous health data API. Used to submit small health data payloads (such as survey responses) without
* incurring the overhead of creating a bunch of small files to upload to S3.
*/
public HealthDataRecord submitHealthData(String appId, StudyParticipant participant, HealthDataSubmission healthDataSubmission) throws IOException, UploadValidationException {
// validate health data submission
if (healthDataSubmission == null) {
throw new InvalidEntityException("Health data submission cannot be null");
}
Validate.entityThrowingException(HealthDataSubmissionValidator.INSTANCE, healthDataSubmission);
// Generate a new uploadId.
String uploadId = BridgeUtils.generateGuid();
// construct health data record
HealthDataRecord record = makeRecordFromSubmission(appId, participant, healthDataSubmission);
// get schema
UploadSchema schema = getSchemaForSubmission(appId, healthDataSubmission);
if (schema != null) {
// sanitize field names in the data node
JsonNode sanitizedData = sanitizeFieldNames(healthDataSubmission.getData());
// Filter data fields and attachments based on schema fields.
filterAttachments(uploadId, schema, sanitizedData, record);
}
// Construct UploadValidationContext for the remaining upload handlers. We don't need all the fields, just the
// ones that these handlers will be using.
UploadValidationContext uploadValidationContext = new UploadValidationContext();
uploadValidationContext.setHealthCode(participant.getHealthCode());
uploadValidationContext.setHealthDataRecord(record);
uploadValidationContext.setAppId(appId);
// For back-compat reasons, we need to make a dummy upload to store the uploadId. This will never be persisted.
// We just need a way to signal the Upload Validation pipeline to use this uploadId.
Upload upload = Upload.create();
upload.setUploadId(uploadId);
uploadValidationContext.setUpload(upload);
// Strict Validation Handler. If this throws, this is an invalid upload (400).
try {
strictValidationHandler.handle(uploadValidationContext);
} catch (UploadValidationException ex) {
throw new BadRequestException(ex);
}
// Transcribe Consent.
transcribeConsentHandler.handle(uploadValidationContext);
// Upload raw JSON as the raw data attachment. This is different from how the upload validation handles it.
// Attachment ID is "[uploadId]-raw.json".
String rawDataAttachmentId = uploadId + RAW_ATTACHMENT_SUFFIX;
String rawDataValue = BridgeObjectMapper.get().writerWithDefaultPrettyPrinter().writeValueAsString(healthDataSubmission.getData());
byte[] rawDataBytes = rawDataValue.getBytes(Charsets.UTF_8);
uploadFileHelper.uploadBytesAsAttachment(rawDataAttachmentId, rawDataBytes);
record.setRawDataAttachmentId(rawDataAttachmentId);
// Upload Artifacts.
uploadArtifactsHandler.handle(uploadValidationContext);
// (depending on attachments). So we need to use the record ID to fetch the record again and return it.
return getRecordById(uploadValidationContext.getRecordId());
}
use of org.sagebionetworks.bridge.upload.UploadValidationException in project BridgeServer2 by Sage-Bionetworks.
the class SmsService method sendSmsMessage.
/**
* Sends an SMS message using the given message provider. User ID is used to fetch the account, so we can get
* health code and time zone and other relevant attributes to log and record as health data. If the recipient
* doesn't have an account (for example, for Intent-to-Participate), this can be left null.
*/
public void sendSmsMessage(String userId, SmsMessageProvider provider) {
checkNotNull(provider);
App app = provider.getApp();
Phone recipientPhone = provider.getPhone();
String message = provider.getFormattedMessage();
// Check max SMS length.
if (message.getBytes(Charset.forName("US-ASCII")).length > SMS_CHARACTER_LIMIT) {
throw new BridgeServiceException("SMS message cannot be longer than 600 UTF-8/ASCII characters.");
}
// Send SMS.
String messageId;
PublishResult result = snsClient.publish(provider.getSmsRequest());
messageId = result.getMessageId();
LOG.info("Sent SMS message, app=" + app.getIdentifier() + ", message ID=" + messageId + ", request ID=" + RequestContext.get().getId());
// Log SMS message.
DateTime sentOn = DateTime.now();
SmsMessage smsMessage = SmsMessage.create();
smsMessage.setPhoneNumber(recipientPhone.getNumber());
smsMessage.setSentOn(sentOn.getMillis());
smsMessage.setMessageBody(message);
smsMessage.setMessageId(messageId);
smsMessage.setSmsType(provider.getSmsTypeEnum());
smsMessage.setAppId(app.getIdentifier());
// Fetch participant, if it exists.
StudyParticipant participant = null;
if (userId != null) {
participant = participantService.getParticipant(app, userId, false);
}
// Finish logging SMS message.
if (participant != null) {
smsMessage.setHealthCode(participant.getHealthCode());
}
Validate.entityThrowingException(SmsMessageValidator.INSTANCE, smsMessage);
messageDao.logMessage(smsMessage);
// If we have a participant, make a health data.
if (participant != null) {
initMessageLogSchema(app.getIdentifier());
// Set sentOn w/ user's time zone, if it exists.
DateTime sentOnWithTimeZone;
if (participant.getTimeZone() != null) {
sentOnWithTimeZone = sentOn.withZone(participant.getTimeZone());
} else {
sentOnWithTimeZone = sentOn.withZone(DateTimeZone.UTC);
}
// Create health data.
ObjectNode healthDataNode = BridgeObjectMapper.get().createObjectNode();
healthDataNode.put(FIELD_NAME_SENT_ON, sentOnWithTimeZone.toString());
healthDataNode.put(FIELD_NAME_SMS_TYPE, provider.getSmsType());
healthDataNode.put(FIELD_NAME_MESSAGE_BODY, message);
// Health Data Service requires app version and phone info. However, this health data is submitted by
// Bridge, not by the app, so fill those in with artificial values.
HealthDataSubmission healthData = new HealthDataSubmission.Builder().withAppVersion(BRIDGE_SERVER_APP_VERSION).withPhoneInfo(BRIDGE_SERVER_PHONE_INFO).withCreatedOn(sentOnWithTimeZone).withSchemaId(MESSAGE_LOG_SCHEMA_ID).withSchemaRevision(MESSAGE_LOG_SCHEMA_REV).withData(healthDataNode).build();
try {
healthDataService.submitHealthData(app.getIdentifier(), participant, healthData);
} catch (IOException | UploadValidationException ex) {
throw new BridgeServiceException(ex);
}
}
}
use of org.sagebionetworks.bridge.upload.UploadValidationException in project BridgeServer2 by Sage-Bionetworks.
the class CRCController method writeReportAndUpdateState.
private int writeReportAndUpdateState(App app, String userId, JsonNode data, String reportName, AccountStates state, boolean useCallerStudyIds) {
String appId = RequestContext.get().getCallerAppId();
AccountId accountId = AccountId.forId(appId, userId);
Account account = accountService.getAccount(accountId).orElseThrow(() -> new EntityNotFoundException(Account.class));
updateState(account, state);
accountService.updateAccount(account);
try {
ObjectNode metadata = JsonNodeFactory.instance.objectNode();
metadata.put("type", reportName);
StudyParticipant participant = participantService.getParticipant(app, account, false);
HealthDataSubmission healthData = new HealthDataSubmission.Builder().withAppVersion("v1").withCreatedOn(getTimestamp()).withMetadata(metadata).withData(data).withPhoneInfo(getUserAgent()).build();
healthDataService.submitHealthData(appId, participant, healthData);
} catch (IOException | UploadValidationException e) {
throw new BridgeServiceException(e);
}
Set<String> callerStudyIds = useCallerStudyIds ? RequestContext.get().getOrgSponsoredStudies() : ImmutableSet.of();
ReportData report = ReportData.create();
report.setDate(JAN1.toString());
report.setData(data);
report.setStudyIds(callerStudyIds);
DateRangeResourceList<? extends ReportData> results = reportService.getParticipantReport(appId, userId, reportName, account.getHealthCode(), JAN1, JAN2);
int status = (results.getItems().isEmpty()) ? 201 : 200;
reportService.saveParticipantReport(appId, userId, reportName, account.getHealthCode(), report);
return status;
}
Aggregations