Git Product home page Git Product logo

fda-mystudies's Introduction

FDA MyStudies

Overview

The FDA’s MyStudies platform enables organizations to quickly build and deploy studies that interact with participants through purpose-built apps on iOS and Android. MyStudies apps can be distributed to participants privately or made available through the App Store and Google Play.

This open-source repository contains the code necessary to run a complete FDA MyStudies instance, inclusive of all web and mobile applications.

Open-source deployment tools are included for semi-automated deployment to Google Cloud Platform (GCP). These tools can be used to deploy the FDA MyStudies platform in just a few hours. These tools follow compliance guidelines to simplify the end-to-end compliance journey. Deployment to other platforms and on-premise systems can be performed manually.

To receive release notifications and other important announcements related to the repository, subscribe to [email protected].

Platform Illustration

Documentation and guides

Information related to the deployment and operation of FDA Mystudies can be found within each directory’s README, and also in the following guides:

For the complete list of FDA MyStudies documentation, visit documentation/README.md.

Platform components and repo organization

Component Intended users Purpose Directories
Study builder Researchers and clinicians No-code user interface for authoring studies (demo screens) study-builder/
study-datastore/
Participant manager Study coordinators No-code user interface to manage participant enrollment (demo screens) participant-manager/
participant-manager-datastore/
Mobile applications Study participants Apps to discover, enroll and participate in studies (demo screens) iOS/
Android/
Response datastore Researchers and analysts Collects and stores participant response data for downstream analysis response-datastore/
Participant datastore Manages participant data such as contact information and consent forms participant-datastore/
Auth Manages account creation, login, logout and resource requests hydra/
auth-server/
Deployment System administrators Infrastructure-as-code to build and maintain platform deployment/

Each high-level directory contains a README.md and the necessary deployment configuration files.

For more information about the platform architecture, visit the Platform overview. An example of how this architecture can be deployed on Google Cloud is diagrammed below.

Example architecture

Data and compliance

FDA MyStudies is designed so that all data stays within the deploying organization’s environment (unless that organization chooses to export their data). Any identifiable data is stored separately from study and response data to help organizations minimize access to sensitive data.

The FDA MyStudies platform has been designed to support auditing requirements for compliance with 21 CFR Part 11, allowing the platform to be used for trials under Investigational New Drug (IND) oversight. If an organization chooses to run FDA MyStudies on Google Cloud, a variety of infrastructure options are available that support HIPAA and other compliance requirements. More information about compliance on Google Cloud and an up-to-date list of products covered under BAA can be found here.

In addition to the platform itself, the open-source deployment tools are designed to assist organizations with their end-to-end compliance journey. Although achieving compliance is the responsibility of the deploying organization, these toolkits enable organizations to deploy FDA MyStudies in a way that helps meet compliance requirements. More details of the deployment patterns used by these automation tools can be found here.

Google Cloud can support compliance with 21 CFR Part 11 regulations when using GCP services in a prescribed manner to handle related data and workloads. While Google has a cloud technology stack ready for many 21 CFR Part 11 compliant workloads, the ultimate compliance determination depends on configuration choices made by the deploying organization.

Release notes

For a detailed list of changes to the FDA MyStudies codebase, see What’s new.

Subscribe to [email protected] to receive release notifications and other important announcements related to the repository.

Feedback

Feature requests and bug reports should be submitted as Github Issues. All feedback is greatly appreciated.


Copyright 2020 Google LLC

fda-mystudies's People

Contributors

amruthbtc avatar aswinijena100 avatar banufirdose-btc1 avatar chiranjibi009 avatar dhanyak-btc avatar eswar1994 avatar firdosebtc1 avatar govindprasadbostontechnologycorporation avatar harisboston avatar jkrogers18 avatar kantharajut-btc avatar karepker avatar kuoyuchi avatar madhud5 avatar madhurya-btc avatar mohangmk avatar monica-btc avatar moschetti avatar naveenr-btc avatar navya-btc avatar nikklassen avatar prakashm181 avatar pujithr avatar rashi-395 avatar rohithd-btc avatar saminguyen avatar tushar-boston avatar wamills avatar yugandhar-btc avatar zohrehj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fda-mystudies's Issues

User emails shouldn't be logged in server log

The current code writes user email in logger.info in 3 places (as part of "EmailNotification - sendEmailNotification() ,Email ="):

  1. auth-server-ws/src/main/java/com/google/cloud/healthcare/fdamystudies/utils/EmailNotification.java
  2. user-registration-server-ws/enroll-mgmt/src/main/java/com/google/cloud/healthcare/fdamystudies/util/EmailNotification.java
  3. user-registration-server-ws/user-mgmt/src/main/java/com/google/cloud/healthcare/fdamystudies/util/EmailNotification.java

We should consider avoid logging the email address for data privacy.

Increase number of textchoice response options required to trigger search bar

(iOS)

It appears that a search bar is rendered in the app after certain number of TextChoice response options are added to a given survey question.

The search bar is a nice feature for a large number of TextChoice response options, but it seems to appear after about 5 options are added. With this smaller number of options, the search bar gets in the way visually and doesn't provide much help.

Can we increase the number of TextChoice response options required to trigger the search bar? Perhaps 10?

I have not tested what other response types use the search bar, but if this is a common behavior across many different response questions, we may want to evaluate the threshold at which it appears for each of these response types.

Uploaded images should be persisted when WCP restarts

For now uploaded images (e.g. study icon) are stored in WCP's local file system: https://github.com/GoogleCloudPlatform/fda-mystudies/blob/early-access/WCP/fdahpStudyDesigner/src/main/resources/application_local.properties#L9

However, in a distributed set up, we might have multiple instances of WCP, and there is no guarantee that all requests goes to the same server. Furthermore, the file is lost if the server restarts.

We should store this in a persistent storage. @ktkonrad has a working prototype which stores images in Cloud Storage.

Response server fails to save result to Firestore

2020-04-03 06:08:03.868  INFO 1 --- [io-8080-exec-10] c.g.c.h.f.service.CommonServiceImpl      : CommonServiceImpl validateAccessToken() - starts 
2020-04-03 06:08:03.967  INFO 1 --- [io-8080-exec-10] .h.f.c.ProcessActivityResponseController : Input values are :
 Study Id: AppTestStudy6
 Activity Id: TestQuestionnaire
 Activity Version: 1.0
 Particpant Id: 082a886d-dae7-4e24-a788-42b103615b02
2020-04-03 06:08:04.045  INFO 1 --- [nio-8080-exec-8] c.g.c.h.f.service.CommonServiceImpl      : CommonServiceImpl validateAccessToken() - starts 
2020-04-03 06:08:04.371  INFO 1 --- [nio-8080-exec-8] c.g.c.h.f.service.CommonServiceImpl      : CommonServiceImpl createActivityLog() - starts 
2020-04-03 06:08:04.373 ERROR 1 --- [io-8080-exec-10] c.g.c.h.f.s.StudyMetadataServiceImpl     : 401 : [no body]

org.springframework.web.client.HttpClientErrorException$Unauthorized: 401 : [no body]
        at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:105) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
        at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:170) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
        at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:112) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
        at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
        at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:785) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
  ...
2020-04-03 06:08:04.416 ERROR 1 --- [io-8080-exec-10] .h.f.c.ProcessActivityResponseController : Could not save response for participant.
 Study Id: AppTestStudy6
 Activity Id: TestQuestionnaire
 Activity Version: 1.0
 Particpant Id: 082a886d-dae7-4e24-a788-42b103615b02


Consolidate mobile app notifications

This behavior was experienced on iOS but is likely present on Android as well. When there are multiple activities scheduled to generate notifications at the same time, those notifications should be consolidated into a single notification that says something like "you have X surveys to complete" rather than generating several redundant push notifications. Screenshot attached.
IMG-4680

Clean up Foundation <-> Swift type conversions

There are a lot conversions between Foundation and Swift Standard Library types.

For example, values which are Foundation types (e.g., NSString) should be immediately converted to Swift Foundation types (e.g., String) such that they do not leak into the overall system.

let nsString: NSString = "Hello, playground"
let string: String = nsString as String
// Use string variable from this point onwards.

Reduce optional properties wherever possible

There are many instances where properties are optional but have a default value.

For example,

var headerParams: [String: String]? = [:]

This creates an unnecessary nillary state which has to be unwrapped before use.

headerParams?["key"] = value

Instead, prefer

var headerParams: [String:String] = [:]
headerParams["key"] = value

Login doesn't work for appCode!="MA"

For appCode != "MA", /register can be successful but appId/orgId are not stored[1]. However, this causes error during /login[3]. IMO we should either disallow register with appCode!="MA", or support login for this case. One possible fix is to support appCode-only lookup here[2].

[1] https://github.com/GoogleCloudPlatform/fda-mystudies/blob/early-access/auth-server-ws/src/main/java/com/google/cloud/healthcare/fdamystudies/controller/AuthenticationController.java#L499
[2] https://github.com/GoogleCloudPlatform/fda-mystudies/blob/early-access/auth-server-ws/src/main/java/com/google/cloud/healthcare/fdamystudies/utils/JwtTokenUtil.java#L148
[3]
2020-04-01T05:21:56.704+0000 INFO JwtTokenUtil getUserId() - starts
Hibernate: select daouserbo0_.id as id1_4_, daouserbo0_.account_status as account_2_4_, daouserbo0_.app_code as app_code3_4_, daouserbo0_.app_id as app_id4_4_, daouserbo0_.created as created5_4_, daouserbo0_.email as email6_4_, daouserbo0_.email_verification_status as email_ve7_4_, daouserbo0_.org_id as org_id8_4_, daouserbo0_.password as password9_4_, daouserbo0_.password_expire_date as passwor10_4_, daouserbo0_.password_updated_date as passwor11_4_, daouserbo0_.reminder_lead_time as reminde12_4_, daouserbo0_.reset_password as reset_p13_4_, daouserbo0_.salt as salt14_4_, daouserbo0_.temp_password as temp_pa15_4_, daouserbo0_.temp_password_date as temp_pa16_4_, daouserbo0_.user_id as user_id17_4_ from users daouserbo0_ where daouserbo0_.email=? and daouserbo0_.app_id=? and daouserbo0_.org_id=? and daouserbo0_.app_code=?
2020-04-01T05:21:56.708+0000 ERROR JwtTokenUtil getUserId() - error()
java.lang.NullPointerException: null
at com.google.cloud.healthcare.fdamystudies.utils.JwtTokenUtil.getUserId(JwtTokenUtil.java:149) [classes/:0.0.1-SNAPSHOT]
at com.google.cloud.healthcare.fdamystudies.utils.JwtTokenUtil.prepareToken(JwtTokenUtil.java:103) [classes/:0.0.1-SNAPSHOT]
at com.google.cloud.healthcare.fdamystudies.utils.JwtTokenUtil.generateToken(JwtTokenUtil.java:55) [classes/:0.0.1-SNAPSHOT]
at com.google.cloud.healthcare.fdamystudies.controller.AuthenticationController.getLoginInformation(AuthenticationController.java:1256) [classes/:0.0.1-SNAPSHOT]
at com.google.cloud.healthcare.fdamystudies.controller.AuthenticationController.login(AuthenticationController.java:654) [classes/:0.0.1-SNAPSHOT]
...

Users should be able to trigger a second verification email

Problem description
Right now If a participant does not get the verification email (e.g. email service malfunction), or loses it (spam folder, delete by accident etc), they will no longer be able to register with that same email address.

Desired outcome:
Show users resend the verification email if the email they try to sign in with is registered but not verified.

WCP call to response server results in 401 error

Logs on WCP:
2020-04-02 18:36:17,079 WARN [http-nio-8080-exec-8] (RestTemplate.java:549) - POST request for "http://35.196.119.71:60000/mystudies-response-server/studymetadata" resulted in 401 (null); invoking error handler 2020-04-02 18:36:17,080 ERROR [http-nio-8080-exec-8] (StudyController.java:5160) - StudyController - submitResponseToResponseServer() - ERROR org.springframework.web.client.HttpClientErrorException: 401 null at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:88) at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:556) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:514) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:472) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:420) at com.fdahpstudydesigner.controller.StudyController.submitResponseToResponseServer(StudyController.java:5151)

verifyEmailId fails with the new release

I'm seeing "POST /myStudiesUserMgmtWS/verifyEmailId HTTP/1.1" 400 with the new release.

Relevant server log:

2020-04-09T22:48:30.717+0000 INFO VerifyEmailIdController verifyEmailId() - starts
2020-04-09T22:48:30.718+0000 INFO FdaEaUserDetailsServiceImpl verifyCode() - calls
2020-04-09T22:48:30.718+0000 INFO FdaEaUserDetailsDaoImpl loadEmailCodeByUserId() - starts
Hibernate: select userdetail0_.user_details_id as user_det1_13_, userdetail0_._ts as _ts2_13_, userdetail0_.app_info_id as app_info3_13_, userdetail0_.code_expire_date as code_exp4_13_, userdetail0_.email as email5_13_, userdetail0
_.email_code as email_co6_13_, userdetail0_.first_name as first_na7_13_, userdetail0_.last_name as last_nam8_13_, userdetail0_.local_notification_flag as local_no9_13_, userdetail0_.locale as locale10_13_, userdetail0_.reminder_lea
d_time as reminde11_13_, userdetail0_.remote_notification_flag as remote_12_13_, userdetail0_.security_token as securit13_13_, userdetail0_.status as status14_13_, userdetail0_.touch_id as touch_i15_13_, userdetail0_.use_pass_code 
as use_pas16_13_, userdetail0_.user_id as user_id17_13_, userdetail0_.verification_date as verific18_13_ from user_details userdetail0_ where userdetail0_.user_id=?
2020-04-09T22:48:30.744+0000 INFO FdaEaUserDetailsDaoImpl loadEmailCodeByUserId() -ends
2020-04-09T22:48:30.745+0000 ERROR VerifyEmailIdController verifyEmailId() - ends: 
com.google.cloud.healthcare.fdamystudies.exceptions.InvalidEmailCodeException: null
        at com.google.cloud.healthcare.fdamystudies.service.FdaEaUserDetailsServiceImpl.verifyCode(FdaEaUserDetailsServiceImpl.java:107) ~[classes/:0.0.1-SNAPSHOT]
        at com.google.cloud.healthcare.fdamystudies.service.FdaEaUserDetailsServiceImpl$$FastClassBySpringCGLIB$$8eec09ee.invoke(<generated>) ~[classes/:0.0.1-SNAPSHOT]
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at com.google.cloud.healthcare.fdamystudies.service.FdaEaUserDetailsServiceImpl$$EnhancerBySpringCGLIB$$30dd0379.verifyCode(<generated>) ~[classes/:0.0.1-SNAPSHOT]
        at com.google.cloud.healthcare.fdamystudies.controller.VerifyEmailIdController.verifyEmailId(VerifyEmailIdController.java:79) [classes/:0.0.1-SNAPSHOT]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]

500 error for /StudyMetaData/versionInfo

Server log on StudyMetaData server (WCP-WS):

2020-04-03 05:16:13,144  INFO [http-nio-8080-exec-3] (AppMetaDataDao.java:562) - INFO: AppMetaDataDao - getAppVersionInfo() :: Starts
Hibernate: select appversion0_.version_info_id as version1_51_, appversion0_.android as android51_, appversion0_.ios as ios51_ from version_info appversion0_
2020-04-03 05:16:13,145  INFO [http-nio-8080-exec-3] (AppMetaDataDao.java:572) - INFO: AppMetaDataDao - getAppVersionInfo() :: Ends
03-Apr-2020 05:16:13.146 SEVERE [http-nio-8080-exec-3] com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
        java.lang.NullPointerException
                at com.hphc.mystudies.integration.AppMetaDataOrchestration.getAppVersionInfo(AppMetaDataOrchestration.java:219)
                at com.hphc.mystudies.service.StudyMetaDataService.getAppVersionInfo(StudyMetaDataService.java:1014)
                at jdk.internal.reflect.GeneratedMethodAccessor81.invoke(Unknown Source)

...

Looks like we are supposed to insert an entry in version_info table. Doesn't look like it's blocking though.

User data should be HTML-escaped for web display

User-defined values should be escaped with the <c:out> tag or fn:escapeXml(). Trying to stop users from entering malicious values won't work unless you prevent them on the server, client-side validators can easily be circumvented.

Survey notifications continue firing when a study is paused

(iOS)

Current behavior:

  1. Study contains a recurring survey
  2. Survey fires notifications whenever a new run is available
  3. Study is "paused" from the Study Builder
  4. Survey notifications are still fired according to the survey schedule even though the study is "paused"
  5. Clicking into a notification that is fired off of a "paused" study results in the user trying to enter the study and receiving the paused study error

Desired behavior:
Notifications should stop firing once a study is paused, but resume once the study is resumed

Remove force unwrapping ("!" syntax)

When dealing with optional properties, there are various means of retrieving a value. Any property access with a "!" suffix is considered dangerous because it causes the application to crash when it is assigned to nil.

For example:

struct MyStruct {
   var myProperty: String?
}

let myStruct = MyStruct()
let property = myStruct.myProperty! // This crashes the app.

Instead, use optional binding

if let property = myStruct.myProperty {
  // Use property non-optionally.
}

In the event that myStruct variable is optional, you may optionally chain.

if let property = myStruct?.myProperty {
}

Avoid the following

let property = myStruct!.myProperty!

Insufficient Permission for consent management

Came across this error on user registration server. Maybe we need to update the configuration on our cloud storage for consent forms. @honkwan can you take a look? Thanks!

2020-04-02T23:35:09.362+0000 ERROR UserConsentManagementController updateEligibilityConsentStatus() - error 
com.google.cloud.storage.StorageException: 403 Forbidden
{
  "error": {
    "code": 403,
    "message": "Insufficient Permission",
    "errors": [
      {
        "message": "Insufficient Permission",
        "domain": "global",
        "reason": "insufficientPermissions"
      }
    ]
  }
}

        at com.google.cloud.storage.spi.v1.HttpStorageRpc.translate(HttpStorageRpc.java:229) ~[google-cloud-storage-1.102.0.jar:1.102.0]
        at com.google.cloud.storage.spi.v1.HttpStorageRpc.open(HttpStorageRpc.java:832) ~[google-cloud-storage-1.102.0.jar:1.102.0]

[app] Go back to intro screen after sign out

After signing out, the app appears the same except the study list is blank. It's not very obvious that the user is signed out. Let's go back to the intro screen (blue screen with 2 buttons) after sign out.

Use HTTPS

iOS apps released to the public need to use HTTPS. It's possible to set an exception, but during app review we have to give the motivation for each exception. It's also good security practice to use TLS.

This should be a setting, where in Debug traffic will go over HTTP, while in Release it'll use HTTPS.

Missing Symbol - iOS linker error

Not sure if this bug is filed under a different title already.
"
iOS linker error when making IPA w/ Product > Archive for target "Generic iOS Device":

Undefined symbols for architecture arm64:

"OBJC_CLASS$_ORKNavigationContainerView", referenced from:

  objc-class-ref in EligibilityStepViewController.o

ld: symbol(s) not found for architecture arm64

clang: error: linker command failed with exit code 1 (use -v to see invocation)

verified that this is the case with both of the latest two changes to date:
1bd2dc9443c82f569906aa335ad792204a150ceb
9651efa279a945e96e980e03934817823c616923
"

Env variable doesn't work in some cases

We are trying to use Kubernetes secrets (which sets env variable in the process) for some configuration. We realized this doesn't work for some cases, including:
[1] In WCP-WS, if we use variables for database user or password (e.g.hibernate.connection.username=${DB_USER}) it is not respected work.
[2] In response-server-ws, we tried to set regServerPartStudyInfoUrl=http://${REGISTRATION_SERVER_URL}/myStudiesEnrollmentMgmt/participantInfo but saw this error message:

2020-04-02 00:11:29,844 ERROR [http-nio-8080-exec-6] (StudyController.java:5123) - StudyController - submitResponseToUserRegistrationServer() - ERROR 
java.lang.IllegalArgumentException: Not enough variable values available to expand 'REGISTRATION_SERVER_URL'
        at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:270)
        at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:208)
...

One possible solution is to substitute all these variables in property files with actual values as one of the step in building the image (perhaps by envsubst). Not sure if this works properly on GKE.

Another path is to make sure all libraries we use to read property files respects env variable. e.g.
We can update the code in [a] to fix [1], etc.

@wamills who is looking into this from our side. It would be great if there is a generic solution for this though.

[1] https://github.com/GoogleCloudPlatform/fda-mystudies/blob/early-access/WCP-WS/src/main/resources/application_local.properties#L30
[2] https://github.com/GoogleCloudPlatform/fda-mystudies/blob/early-access/response-server-ws/src/main/resources/application-appConfig.properties#L45

[a] https://github.com/GoogleCloudPlatform/fda-mystudies/blob/early-access/WCP-WS/src/main/java/com/hphc/mystudies/util/HibernateUtil.java#L49

User-specific study resources

We want to add user-specific resources to the study resource screen.

The existing /StudyMetaData/resources?studyId=<study_id> endpoint only serves resources that are common to the study.

Can we add an endpoint, /getUserResources?studyId=<study_id> to return user specific resources for a study? The request header should include userid, clienttoken and accesstoken. The response will have the same format as the /StudyMetaData/resources?studyId=<study_id> endpoint. The iOS and Android app should call this additional API in the resource screen and display both types of resources.

To begin with can we connect the new API end-to-end to iOS and Android apps with an empty implementation for fetching the actual resources on the backend?

@kuoyuchi @jkrogers18

Simplify the filtering options on the study list in the mobile app

When selecting the filter icon on the study list screen of the mobile app the user is presented with many different filtering options. Many of the categories don't apply. Does it make sense to remove the categories section on this screen? This allows the "Study Status" options to occupy the left side of the screen and the "Participation Status" on the right side of the screen. Screenshot attached.

filtering

Unable to export consent document on iOS app

(iPhone X 13.3.1) After completing the consent and viewing the PDF version, there is a 'export' icon that I would expect to allow me to save the PDF locally or to send via email (bottom left corner in attached screenshot). However clicking this icon results in no action. This appears to be a persistent bug across all PDFs in the mobile app (e.g. the app glossary document in the resources section has the same problem).

3664

Provide default image for thumbnail images in the mobile app study list

It looks like the default thumbnail for studies in the study list is a grey box. Is it possible to create a simple and generic thumbnail for this? Perhaps just the blue or grey stroke of a circle on a white background or the same icon we are using for the app itself? Screenshot attached.

overlays

Remove overlays from the thumbnail images on mobile app study list

There is white text with a black background overlaid on the thumbnail images of the mobile app study list. This may not be necessary for many MyStudies implementations and adds visual complexity for the participant. Is it possible to turn this off by default? Screenshot attached.

overlays

Study list displayed after logout

After logging out, the app still displays a list of studies. If you tap on a study, it'll take you back to the login screen. This is confusing.

Remove Implicitly Unwrapped Optionals

Property/variable declarations should not be an Implicitly Unwrapped Optional type. The only valid use case is @IBOutlets because they should be strong references. (See: #174)

For example:

struct FailedUserServices {
  var requestParams: [String: Any]? = [:]
  var headerParams: [String: String]? = [:]
  var method: Method!
}

The method property is an Implicitly Unwrapped Optional. This means that there must be an instance assigned to the method property prior to first access, otherwise the application will crash.

Instead, prefer

struct SomeClass {
  let requestParams: [String: Any]
  let headerParams: [String: String]
  let method: Method
}

let requestParams = <#Param#> ?? [:]
SomeClass(requestParams: requestParams, ...)

Time zone handled incorrectly

The date strings returned from WCP are in UTC time, e.g. "startTime": "2020-04-03T00:00:00.000+0000". The app ignores the time zone when converting the string to a Date object, resulting in the wrong time.

`ERROR: Field 'log_id' doesn't have a default value` in user registration server

$ kubectl logs user-registration-server-ws-5559fd7d66-xxvzz user-registration-ws
Snippet of logs from server
Hibernate: insert into activity_log (activity_date_time, actvity_name, activity_description, auth_user_id, activity_log_id) values (?, ?, ?, ?, ?)
2020-04-16T17:22:22.422+0000 WARN SQL Error: 1364, SQLState: HY000
2020-04-16T17:22:22.423+0000 ERROR Field 'log_id' doesn't have a default value
2020-04-16T17:22:22.425+0000 ERROR HHH000346: Error during managed flush [org.hibernate.exception.GenericJDBCException: could not execute statement]
2020-04-16T17:22:22.423+0000 WARN SQL Error: 1364, SQLState: HY000
2020-04-16T17:22:22.426+0000 ERROR Field 'log_id' doesn't have a default value
2020-04-16T17:22:22.427+0000 ERROR HHH000346: Error during managed flush [org.hibernate.exception.GenericJDBCException: could not execute statement]
2020-04-16T17:22:22.447+0000 ERROR CommonServiceImpl createActivityLog() - error
org.springframework.orm.jpa.JpaSystemException: could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:351) ~[spring-orm-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253) ~[spring-orm-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536) ~[spring-orm-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:534) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:305) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at com.sun.proxy.$Proxy366.save(Unknown Source) ~[?:?]
        at com.google.cloud.healthcare.fdamystudies.service.CommonServiceImpl.createActivityLog(CommonServiceImpl.java:93) [classes/:0.0.1-SNAPSHOT]
        at com.google.cloud.healthcare.fdamystudies.controller.UserConsentManagementController.updateEligibilityConsentStatus(UserConsentManagementController.java:179) [classes/:0.0.1-SNAPSHOT]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) [spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) [spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.1.8.RELEASE.jar:5

(etc.)

/mystudies-response-server/participant/get-activity-state returns 400

After enrolling in a study, app flashes "no activities available right now". It seems like it's spinner on get-activity-state.

Request:

Host: 35.196.119.71:60000
appId: GCPMS001
Accept: */*
userId: Z55SpjZ4ceYBxz7-G1IxGqeqN4Fn12S-7wH7MOlzz4gy5Qq
clientToken: qG182wSrQJ9NdDU-lhTlHFkZwVRwaBD-SHeD1QeaViGv7Ji
orgId: OrgName
Accept-Language: en-us
Accept-Encoding: gzip, deflate
accessToken: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJmb29AYmFyLmNvbSIsIkF1dGhvcml0aWVzIjpbXSwiaWF0IjoxNTg1ODgyOTY0fQ.1j5s1H7xzZg5bd4QkFP9bnbnc1uZsQBICr-hgCE8WYYxNLcdXqjJbpQ74PaBX9xLFvVo8cleEeMWhohZ519gVQ
Content-Type: application/json
User-Agent: GCPMyStudies/1 CFNetwork/1121.2.2 Darwin/19.3.0
Connection: keep-alive

Response:

Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD
code: 701
userMessage: Invalid Input
type: Error
detailMessage: The argument that you provided is a required argument but it is blank or null.
Transfer-Encoding: chunked
Date: Fri, 03 Apr 2020 03:11:45 GMT
Proxy-Connection: close

UserRegistrationServer built from head fails to start

Seeing this error message:

2020-04-09T22:29:49.797+0000 WARN Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.spring
framework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'beanConfig': Unsatisfied dependency expressed through field 'appConfig'; nested exception is org.springframework.beans.factory.BeanCreationExcep
tion: Error creating bean with name 'applicationPropertyConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'ios.push.notification.type' 
in value "${ios.push.notification.type}"
2020-04-09T22:29:49.824+0000 INFO 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-04-09T22:29:49.830+0000 ERROR Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'beanConfig': Unsatisfied depe
ndency expressed through field 'appConfig'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applicationPropertyConfiguration': Injection of autowired dependencies failed; 
nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'ios.push.notification.type' in value "${ios.push.notification.type}"

Unable to save "Daily" questionnaire scheduling setting in study builder

After selecting the "Daily" for the questionnaire frequency when adding or editing a questionnaire, filling out the required settings, and saving the settings, the scheduling settings will appear to have been saved without error. However, going back to the main "Questionnaires" page and clicking on view or edit settings on the questionnaire shows that the settings have been reverted to the default setting ("One Time").

Adjust timing of push notifications to match survey availability

(iOS)

Issue:

  1. I receive a push notification informing me that a survey is available to complete
  2. I navigate to the survey, but it is still marked as "Completed" from the last run
  3. After some small period of time I can refresh the activities page and see that the survey is now available

Ideally we adjust timing so that the survey is always available by the time the user receives the push notification.

WCP call to registration server fails with 400 error

Error message on WCP:

2020-04-02 18:36:16,944  WARN [http-nio-8080-exec-8] (RestTemplate.java:549) - POST request for "http://35.196.79.108:60000/myStudiesUserMgmtWS/studies/studymetadata" resulted in 400 (null)
; invoking error handler
2020-04-02 18:36:16,950 ERROR [http-nio-8080-exec-8] (StudyController.java:5123) - StudyController - submitResponseToUserRegistrationServer() - ERROR 
org.springframework.web.client.HttpClientErrorException: 400 null
        at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:88)

Error message on User Registration server:

2020-04-02T18:36:16.462+0000 INFO /studies/studymetadata
2020-04-02T18:36:16.511+0000 INFO StudiesController - addUpdateStudyMetadata() : starts
2020-04-02T18:36:16.512+0000 INFO StudiesServicesImpl - saveStudyMetadata() : starts
2020-04-02T18:36:16.547+0000 INFO StudiesDaoImpl - saveStudyMetadata() : Starts
Hibernate: select studyinfob0_.id as id1_10_, studyinfob0_.app_info_id as app_inf16_10_, studyinfob0_.category as category2_10_, studyinfob0_.created_by as created_3_10_, studyinfob0_.created_on as created_4_10_, studyinfob0_.custom_id as custom_i5_10_, studyinfob0_.description as descript6_10_, studyinfob0_.enrolling as enrollin7_10_, studyinfob0_.modified_by as modified8_10_, studyinfob0_.modified_date as modified9_10_, studyinfob0_.name as name10_10_, studyinfob0_.sponsor as sponsor11_10_, studyinfob0_.status as status12_10_, studyinfob0_.tagline as tagline13_10_, studyinfob0_.type as type14_10_, studyinfob0_.version as version15_10_ from study_info studyinfob0_ where studyinfob0_.custom_id=?
Hibernate: select appinfodet0_.app_info_id as app_info1_1_, appinfodet0_.android_bundle_id as android_2_1_, appinfodet0_.android_server_key as android_3_1_, appinfodet0_.app_description as app_desc4_1_, appinfodet0_.custom_app_id as custom_a5_1_, appinfodet0_.app_name as app_name6_1_, appinfodet0_.created_by as created_7_1_, appinfodet0_.created_on as created_8_1_, appinfodet0_.forgot_email_body as forgot_e9_1_, appinfodet0_.forgot_email_sub as forgot_10_1_, appinfodet0_.from_email_id as from_em11_1_, appinfodet0_.from_email_password as from_em12_1_, appinfodet0_.ios_bundle_id as ios_bun13_1_, appinfodet0_.ios_certificate as ios_cer14_1_, appinfodet0_.ios_certificate_password as ios_cer15_1_, appinfodet0_.method_handler as method_16_1_, appinfodet0_.modified_by as modifie17_1_, appinfodet0_.modified_date as modifie18_1_, appinfodet0_.org_info_id as org_inf21_1_, appinfodet0_.reg_email_body as reg_ema19_1_, appinfodet0_.reg_email_sub as reg_ema20_1_ from app_info appinfodet0_ where appinfodet0_.custom_app_id=?
Hibernate: select orginfo0_.id as id1_5_0_, orginfo0_.created_by as created_2_5_0_, orginfo0_.created_on as created_3_5_0_, orginfo0_.modified_by as modified8_5_0_, orginfo0_.modified_date as modified9_5_0_, orginfo0_.name as name6_5_0_, orginfo0_.org_id as org_id10_5_0_ from org_info orginfo0_ where orginfo0_.id=?
Hibernate: select orginfo0_.id as id1_5_, orginfo0_.created_by as created_2_5_, orginfo0_.created_on as created_3_5_, orginfo0_.modified_by as modified8_5_, orginfo0_.modified_date as modified9_5_, orginfo0_.name as name6_5_, orginfo0_.org_id as org_id10_5_ from org_info orginfo0_ where orginfo0_.org_id=?
Hibernate: insert into study_info (app_info_id, category, created_by, created_on, custom_id, description, enrolling, modified_by, modified_date, name, sponsor, status, tagline, type, version) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select locationbo0_.id as id1_3_, locationbo0_.created as created2_3_, locationbo0_.created_by as created_3_3_, locationbo0_.custom_id as custom_i4_3_, locationbo0_.description as descript5_3_, locationbo0_.is_default as is_defau6_3_, locationbo0_.name as name7_3_, locationbo0_.status as status8_3_ from locations locationbo0_ where locationbo0_.is_default='Y'
2020-04-02T18:36:16.890+0000 ERROR StudiesDaoImpl - saveStudyMetadata() : error 
javax.persistence.NoResultException: No entity found for query

Entering app via notification should land user in correct activity

(iOS)

The mobile application fires notifications when a new activity is ready. When clicking one of these notifications, the user is navigated to the MyStudies app. The app opens to the last screen the user was on (as if I had just opened the app from the home screen). The expected behavior would be for the app to open to the activity that fired that notification. Can we change the notification behavior to match this expected behavior?

Feedback and Contact Us emails were being fired from the WCP server so these are shifted to User Management bundle

Hi @zohrehj @nikklassen

Feedback and Contact Us emails were being fired from the WCP server and this has now been moved to be fired from the UR server (User Management bundle). This change was required because Feedback and Contact Us forms contain information submitted by Participants and also their email (in case of CU) so it is more secure to not have these go to the WCP server that does not handle any participant-related data.

We have handled these code changes and wants to a raise a PR for this. This change requires WCP WS and User Mgmt bundle redeployments. Kindly confirm on this so that we can raise this PR with these code changes
FYI @aswinijena100

Update text of password reset error message

(iOS)

If attempting to reset a password using an email address that was not previously verified, an error message is presented. The error message seems to have the wrong text. The message asks a question, but the only response option is "ok." Screenshot attached.

IMG-4692

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.