Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions backends/carp_webservices/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 3.8.0

* anonymous authentication
* upgrading packages

## 3.7.0

* fix of issues [#467](https://github.com/cph-cachet/carp.sensing-flutter/issues/467)
Expand Down
106 changes: 63 additions & 43 deletions backends/carp_webservices/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This package uses the [oidc](https://pub.dev/packages/oidc) plugin for authentic
### Android

On Android you need to edit both the `build.gradle` file and the `AndroidManifest.xml` file plus disable some backup settings.
You also need to add an activity to the `AndroidManifest.xml` to allow for redirection to/from the web view for authentication (if you are using the `authenticate()` method in the package). You manifest file would look something like this:
You also need to add an activity to the `AndroidManifest.xml` to allow for redirection to/from the web view for authentication (if you are using the `authenticate()` or `authenticateWithMagicLink` methods in the package). You manifest file would look something like this:

```xml
...
Expand All @@ -31,7 +31,7 @@ You also need to add an activity to the `AndroidManifest.xml` to allow for redir
android:name="${applicationName}"
android:label="CAWS Example"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/data_extraction_rules"
android:dataExtractionRules="@xml/data_extraction_rules"
android:icon="@mipmap/ic_launcher">

<!-- Used by authentication redirect to/from web view -->
Expand All @@ -55,6 +55,18 @@ You also need to add an activity to the `AndroidManifest.xml` to allow for redir
<data android:pathPrefix="/auth" />
</intent-filter>
</activity>

<!-- Used by authentication redirect to/from web view for anonymous users -->
<activity
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
android:exported="true">
<intent-filter android:label="flutter_web_auth_2">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="caws-example-app" android:pathPrefix="/" />
</intent-filter>
</activity>
```

### iOS
Expand All @@ -70,31 +82,32 @@ Add the following `CFBundleURLTypes` entry in your `Info.plist` file:
<key>CFBundleURLSchemes</key>
<array>
<string>com.my.app</string>
<string>my-redirect-uri</string>
</array>
</dict>
</array>
```

Replace `com.my.app` with your application id.
Replace `com.my.app` with your application id and `my-redirect-url` with your redirect uri.

## Services

CARP Web Services (CAWS) consists of a set of sub-services, which are accessible for the client:

* [`CarpAuthService`](https://pub.dev/documentation/carp_webservices/latest/carp_auth/CarpAuthService-class.html) - authentication service for CAWS
* [`CarpParticipationService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpParticipationService-class.html) - CAWS-specific implementation of the [ParticipationService](https://github.com/cph-cachet/carp.core-kotlin/blob/develop/docs/carp-deployments.md#participationservice)
* [`CarpDeploymentService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpDeploymentService-class.html) - CAWS-specific implementation of the [DeploymentService](https://github.com/cph-cachet/carp.core-kotlin/blob/develop/docs/carp-deployments.md#deploymentservice)
* [`CarpDataStreamService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpDataStreamService-class.html) - CAWS-specific implementation of the [DataStreamService](<https://github.com/cph-cachet/carp.core-kotlin/blob/develop/docs/carp-data.md#datastreamservice>)
* [`CarpService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpService-class.html) - resource management (folders, documents, and files) and alternative data management service
- [`CarpAuthService`](https://pub.dev/documentation/carp_webservices/latest/carp_auth/CarpAuthService-class.html) - authentication service for CAWS
- [`CarpParticipationService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpParticipationService-class.html) - CAWS-specific implementation of the [ParticipationService](https://github.com/cph-cachet/carp.core-kotlin/blob/develop/docs/carp-deployments.md#participationservice)
- [`CarpDeploymentService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpDeploymentService-class.html) - CAWS-specific implementation of the [DeploymentService](https://github.com/cph-cachet/carp.core-kotlin/blob/develop/docs/carp-deployments.md#deploymentservice)
- [`CarpDataStreamService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpDataStreamService-class.html) - CAWS-specific implementation of the [DataStreamService](https://github.com/cph-cachet/carp.core-kotlin/blob/develop/docs/carp-data.md#datastreamservice)
- [`CarpService`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CarpService-class.html) - resource management (folders, documents, and files) and alternative data management service

The `CarpParticipationService`, `CarpDeploymentService`, and `CarpDataStreamService` follows the [CARP Core architecture](https://github.com/cph-cachet/carp.core-kotlin?tab=readme-ov-file#architecture), and are CAWS-specific implementations of the ParticipationService, DeploymentService, and DataStreamService, respectively.
The`CarpAuthService` and `CarpService` are only part of the CAWS architecture ("non-core" endpoints).

## Configuration

All CAWS services needs to be configured before used, using the `configure` method taking a [`CarpApp`](https://pub.dev/documentation/carp_webservices/latest/carp_services/CarpApp-class.html) configuration.
All CAWS services needs to be configured before used, using the `configure` method taking a [`CarpApp`](https://pub.dev/documentation/carp_webservices/latest/carp_services/CarpApp-class.html) configuration.

````dart
```dart
// The URI of the CAWS server to connect to.
final Uri uri = Uri(
scheme: 'https',
Expand All @@ -108,7 +121,7 @@ final CarpApp app = CarpApp(

// Configure the CARP Service with this app.
CarpService().configure(app);
````
```

The singleton can now be accessed via `CarpService()`.

Expand All @@ -126,8 +139,9 @@ Authentication is done using the `CarpAuthService` singleton, which is configure
// The authentication configuration
late CarpAuthProperties authProperties = CarpAuthProperties(
authURL: uri,
clientId: 'studies-app',
redirectURI: Uri.parse('carp-studies-auth://auth'),
clientId: 'my-client-id',
redirectURI: Uri.parse('my-redirect-uri:/my-path'),
anonymousRedirectURI: Uri.parse('my-redirect-uri:/my-anonymous-user-path'),
// For authentication at CAWS the path is '/auth/realms/Carp'
discoveryURL: uri.replace(pathSegments: [
'auth',
Expand All @@ -148,7 +162,7 @@ CarpUser user = await CarpAuthService().authenticate();
This [`CarpUser`](https://pub.dev/documentation/carp_webservices/latest/carp_auth/CarpUser-class.html) object contains the OAuth token in the `token` (of type [`OAuthToken`](https://pub.dev/documentation/carp_webservices/latest/carp_auth/OAuthToken-class.html)) parameter.
Since the `CarpUser` object can be serialized to JSON, the user and the (valid) OAuth token can be stored on the phone.

To refresh the OAuth token the client (Flutter) simply call:
The OAuth token can be refreshed by calling the `refresh()` method:

```dart
await CarpAuthService().refresh()
Expand All @@ -162,6 +176,12 @@ To authenticate using username and password without opening the web view, use th
CarpUser user = await CarpAuthService().authenticateWithUsernamePassword('username', 'password');
```

To authenticate using a magic link (e.g., as read from a QR code) use the `authenticateWithMagicLink` method. This method takes the URL as a `String` parameter, authenticates the user, and generates and returns a `CarpUser` object.

```dart
CarpUser user = await CarpAuthService().authenticateWithMagicLink(qrcode);
```

To log out, just call the `logout` or `logoutNoContext` methods:

```dart
Expand All @@ -172,15 +192,15 @@ await CarpAuthService().logout()

A core notion of CARP is the [Deployment](https://github.com/cph-cachet/carp.core-kotlin/blob/develop/docs/carp-deployments.md) subsystem, which has two services:

* **Participation Service** - allows retrieving participation information for study deployments, and managing data related to participants which is input by users.
* **Deployment Service** - allows for retrieving primary device deployments for participating primary devices as defined in the study protocol.
- **Participation Service** - allows retrieving participation information for study deployments, and managing data related to participants which is input by users.
- **Deployment Service** - allows for retrieving primary device deployments for participating primary devices as defined in the study protocol.

### Participation Service

Enables the client to get invitations for a specific `accountId`, i.e. a user. Default is the user who is authenticated to the CARP Service.

```dart
// We assume that we are authenticated to CAWS and that the CarpService()
// We assume that we are authenticated to CAWS and that the CarpService()
// instance has been configured.

// configure from another CAWS service
Expand Down Expand Up @@ -286,7 +306,7 @@ The Deployment Service handles "deployment" configurations, i.e. configurations
The [`CarpDeploymentService`](https://pub.dev/documentation/carp_webservices/latest/carp_services/CarpDeploymentService-class.html) has methods for getting deployments and for updating deployment and device status. Here are a list of examples:

```dart
// We assume that we are authenticated to CAWS and that the CarpService()
// We assume that we are authenticated to CAWS and that the CarpService()
// instance has been configured.

CarpDeploymentService().configureFrom(CarpService());
Expand Down Expand Up @@ -317,9 +337,9 @@ await CarpDeploymentService().deviceDeployed(

However, instead of keeping track of deployment IDs, a more convenient way to access deployments are to use a [`DeploymentReference`](https://pub.dev/documentation/carp_webservices/latest/carp_services/DeploymentReference-class.html):

````dart
// We assume that we are authenticated to CAWS, that the CarpService()
// instance has been configured, and that the deployment information has
```dart
// We assume that we are authenticated to CAWS, that the CarpService()
// instance has been configured, and that the deployment information has
// be saved by setting the invitation (using the 'setInvitation' method).

CarpDeploymentService().configureFrom(CarpService());
Expand All @@ -340,7 +360,7 @@ var deployment = await deploymentReference.get();

// mark the deployment as a successfully deployed
status = await deploymentReference.deployed();
````
```

## Data Stream Service

Expand Down Expand Up @@ -380,10 +400,10 @@ However, you would rarely need to use these endpoints in your app, since the [ca
The [`CarpService`](https://pub.dev/documentation/carp_webservices/latest/carp_services/CarpService-class.html) provides access to a set of "non-core" endpoints in CAWS.
These "non-core" endpoints are:

* JSON Documents organized in Collections
* File Management
* Informed Consent Documents
* Data Points
- JSON Documents organized in Collections
- File Management
- Informed Consent Documents
- Data Points

All of these endpoints can be considered as additional "resources" which are available for up- or download from clients.

Expand All @@ -393,10 +413,10 @@ CARP Web Service supports storing JSON documents in nested collections.

A [`CollectionReference`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/CollectionReference-class.html) is used to access collections and a [`DocumentReference`](https://pub.dev/documentation/carp_webservices/latest/carp_services/DocumentReference-class.html) is used to access documents. Both of these can be used to:

* creating, updating, and deleting documents
* accessing documents in collections
- creating, updating, and deleting documents
- accessing documents in collections

`````dart
```dart
// access a document
// - if the document id is not specified, a new document (with a new id)
// is created
Expand Down Expand Up @@ -428,23 +448,23 @@ List<String> collections = newDocument.collections;
// get all documents in a collection.
List<DocumentSnapshot> documents =
await CarpService().collection('users').documents;
`````
```

### File Management

CARP Web Service supports storing raw binary file.

A [`FileStorageReference`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/FileStorageReference-class.html) is used to manage files and have methods for:

* uploading a file
* downloading a file
* getting a file object
* getting all file objects
* deleting a file
- uploading a file
- downloading a file
- getting a file object
- getting all file objects
- deleting a file

When uploading a file, you can add metadata as a `Map<String, String>`.

````dart
```dart
// first upload a file
final File uploadFile = File('test/img.jpg');
final FileUploadTask uploadTask = CarpService()
Expand Down Expand Up @@ -474,7 +494,7 @@ final List<CarpFileResponse> results =

// finally, delete the file
responseCode = await CarpService().getFileStorageReference(id).delete();
````
```

### Informed Consent Document

Expand Down Expand Up @@ -504,12 +524,12 @@ try {

A [`DataPointReference`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/DataPointReference-class.html) is used to manage [`DataPoint`](https://pub.dartlang.org/documentation/carp_webservices/latest/carp_services/DataPoint-class.html) objects on a CARP Web Service, and have CRUD methods for:

* post a data point
* batch upload multiple data points
* get a data point
* delete data points
- post a data point
- batch upload multiple data points
- get a data point
- delete data points

````dart
```dart
// Create a piece of data
final lightData = AmbientLight(
maxLux: 12,
Expand All @@ -535,7 +555,7 @@ await CarpService().getDataPointReference().batchPostDataPoint(file);

// delete the data point
await CarpService().getDataPointReference().deleteDataPoint(dataPointId);
````
```

## Features and bugs

Expand Down
11 changes: 8 additions & 3 deletions backends/carp_webservices/example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ android {
ndkVersion = flutter.ndkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
coreLibraryDesugaringEnabled true
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
jvmTarget = JavaVersion.VERSION_17
}

sourceSets {
Expand Down Expand Up @@ -52,3 +53,7 @@ android {
flutter {
source '../..'
}

dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />

<application
android:name="${applicationName}"
android:label="CAWS Example"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/data_extraction_rules"
android:icon="@mipmap/ic_launcher">
<application
android:name="${applicationName}"
android:label="CAWS Example"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/data_extraction_rules"
android:icon="@mipmap/ic_launcher">

<!-- Used by authentication redirect to/from web view -->
<activity
Expand Down Expand Up @@ -63,6 +64,18 @@
</intent-filter>
</activity>

<!-- Used by authentication redirect to/from web view for anonymous users -->
<activity
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
android:exported="true">
<intent-filter android:label="flutter_web_auth_2">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="caws-example-app" android:pathPrefix="/" />
</intent-filter>
</activity>

<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.enableJetifier=false
android.enableR8=true
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
6 changes: 3 additions & 3 deletions backends/carp_webservices/example/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ pluginManagement {
}

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
id "dev.flutter.flutter-plugin-loader" version "1.0.2"
id "com.android.application" version "8.9.0" apply false
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}

include ":app"
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
<string>13.0</string>
</dict>
</plist>
9 changes: 8 additions & 1 deletion backends/carp_webservices/example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
platform :ios, '14.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down Expand Up @@ -37,6 +37,13 @@ target 'Runner' do
end

post_install do |installer|
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0'
end
end
end
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
Expand Down
Loading