diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 7145ba67..6230f5a8 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -11,10 +11,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up JDK 17
- uses: actions/setup-java@v1
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
+ distribution: temurin
java-version: 17
- name: Prepare environment
env:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f120643..3cc0dc98 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,19 @@
# Change Log
+## 24.1.0
+
+* Added: Realtime `presences` channel and `RealtimePresence` types for presence subscriptions
+* Added: `Advisor` and `Presences` services
+* Added: `Insight`, `Presence`, and `Report` models with list variants
+* Added: `fusionauth`, `keycloak`, and `kick` providers to `OAuthProvider` enum
+* Updated: Migrated Gradle build files to Kotlin DSL (`build.gradle.kts`)
+* Updated: `X-Appwrite-Response-Format` header to `1.9.5`
+
## 24.0.0
-* Breaking: Added `unsubscribe()`, `update()`, and `close()` for Realtime subscription lifecycle.
-* Added: Added `userPhone` to the `Membership` model.
-* Updated: Updated `X-Appwrite-Response-Format` header to `1.9.2`.
+* Breaking: Added `unsubscribe()`, `update()`, and `close()` to Realtime subscriptions
+* Added: Added `userPhone` field to `Membership` model
+* Updated: Updated `X-Appwrite-Response-Format` header to `1.9.2`
## 23.1.0
diff --git a/README.md b/README.md
index 1e2528ba..d09a8ee9 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@


-
+
[](https://travis-ci.com/appwrite/sdk-generator)
[](https://twitter.com/appwrite)
[](https://appwrite.io/discord)
@@ -38,7 +38,7 @@ repositories {
Next, add the dependency to your project's `build.gradle(.kts)` file:
```groovy
-implementation("io.appwrite:sdk-for-android:24.0.0")
+implementation("io.appwrite:sdk-for-android:24.1.0")
```
### Maven
@@ -49,7 +49,7 @@ Add this to your project's `pom.xml` file:
io.appwrite
sdk-for-android
- 24.0.0
+ 24.1.0
```
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index a1957d4a..00000000
--- a/build.gradle
+++ /dev/null
@@ -1,33 +0,0 @@
-apply plugin: 'io.github.gradle-nexus.publish-plugin'
-
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-buildscript {
- ext.kotlin_version = "1.9.10"
-
- version System.getenv("SDK_VERSION")
-
- repositories {
- maven { url "https://plugins.gradle.org/m2/" }
- google()
- mavenCentral()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:8.2.2"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath "io.github.gradle-nexus:publish-plugin:1.3.0"
- }
-}
-
-allprojects {
- repositories {
- google()
- mavenCentral()
- }
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
-
-apply from: "${rootDir}/scripts/publish-config.gradle"
-
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 00000000..d5244701
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,43 @@
+import java.util.Properties
+
+plugins {
+ id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
+ id("com.android.library") version "9.1.1" apply false
+ id("com.android.application") version "9.1.1" apply false
+}
+
+version = System.getenv("SDK_VERSION") ?: "0.0.0"
+
+tasks.register("clean") {
+ delete(rootProject.layout.buildDirectory)
+}
+
+val signingKeyId: String = System.getenv("SIGNING_KEY_ID") ?: ""
+val signingPassword: String = System.getenv("SIGNING_PASSWORD") ?: ""
+val signingSecretKeyRingFile: String = System.getenv("SIGNING_SECRET_KEY_RING_FILE") ?: ""
+val ossrhUsername: String = System.getenv("OSSRH_USERNAME") ?: ""
+val ossrhPassword: String = System.getenv("OSSRH_PASSWORD") ?: ""
+val sonatypeStagingProfileId: String = System.getenv("SONATYPE_STAGING_PROFILE_ID") ?: ""
+
+val secretPropsFile = project.rootProject.file("local.properties")
+val localProperties = Properties().apply {
+ if (secretPropsFile.exists()) {
+ secretPropsFile.inputStream().use { load(it) }
+ }
+}
+
+extra["signing.keyId"] = signingKeyId.ifEmpty { localProperties.getProperty("signing.keyId", "") }
+extra["signing.password"] = signingPassword.ifEmpty { localProperties.getProperty("signing.password", "") }
+extra["signing.secretKeyRingFile"] = signingSecretKeyRingFile.ifEmpty { localProperties.getProperty("signing.secretKeyRingFile", "") }
+
+nexusPublishing {
+ repositories {
+ sonatype {
+ stagingProfileId.set(sonatypeStagingProfileId.ifEmpty { localProperties.getProperty("sonatypeStagingProfileId", "") })
+ username.set(ossrhUsername.ifEmpty { localProperties.getProperty("ossrhUsername", "") })
+ password.set(ossrhPassword.ifEmpty { localProperties.getProperty("ossrhPassword", "") })
+ nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
+ snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
+ }
+ }
+}
diff --git a/docs/examples/java/advisor/get-insight.md b/docs/examples/java/advisor/get-insight.md
new file mode 100644
index 00000000..9ca79e42
--- /dev/null
+++ b/docs/examples/java/advisor/get-insight.md
@@ -0,0 +1,25 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.services.Advisor;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Advisor advisor = new Advisor(client);
+
+advisor.getInsight(
+ "", // reportId
+ "", // insightId
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/advisor/get-report.md b/docs/examples/java/advisor/get-report.md
new file mode 100644
index 00000000..6382cd33
--- /dev/null
+++ b/docs/examples/java/advisor/get-report.md
@@ -0,0 +1,24 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.services.Advisor;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Advisor advisor = new Advisor(client);
+
+advisor.getReport(
+ "", // reportId
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/advisor/list-insights.md b/docs/examples/java/advisor/list-insights.md
new file mode 100644
index 00000000..dd18ce82
--- /dev/null
+++ b/docs/examples/java/advisor/list-insights.md
@@ -0,0 +1,26 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.services.Advisor;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Advisor advisor = new Advisor(client);
+
+advisor.listInsights(
+ "", // reportId
+ List.of(), // queries (optional)
+ false, // total (optional)
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/advisor/list-reports.md b/docs/examples/java/advisor/list-reports.md
new file mode 100644
index 00000000..14f5b89b
--- /dev/null
+++ b/docs/examples/java/advisor/list-reports.md
@@ -0,0 +1,25 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.services.Advisor;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Advisor advisor = new Advisor(client);
+
+advisor.listReports(
+ List.of(), // queries (optional)
+ false, // total (optional)
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/presences/delete.md b/docs/examples/java/presences/delete.md
new file mode 100644
index 00000000..04dace36
--- /dev/null
+++ b/docs/examples/java/presences/delete.md
@@ -0,0 +1,24 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.services.Presences;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Presences presences = new Presences(client);
+
+presences.delete(
+ "", // presenceId
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/presences/get.md b/docs/examples/java/presences/get.md
new file mode 100644
index 00000000..8417a566
--- /dev/null
+++ b/docs/examples/java/presences/get.md
@@ -0,0 +1,24 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.services.Presences;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Presences presences = new Presences(client);
+
+presences.get(
+ "", // presenceId
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/presences/list.md b/docs/examples/java/presences/list.md
new file mode 100644
index 00000000..e23f49a2
--- /dev/null
+++ b/docs/examples/java/presences/list.md
@@ -0,0 +1,26 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.services.Presences;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Presences presences = new Presences(client);
+
+presences.list(
+ List.of(), // queries (optional)
+ false, // total (optional)
+ 0, // ttl (optional)
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/presences/update.md b/docs/examples/java/presences/update.md
new file mode 100644
index 00000000..b38a10f0
--- /dev/null
+++ b/docs/examples/java/presences/update.md
@@ -0,0 +1,31 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.Permission;
+import io.appwrite.Role;
+import io.appwrite.services.Presences;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Presences presences = new Presences(client);
+
+presences.update(
+ "", // presenceId
+ "", // status (optional)
+ "2020-10-15T06:38:00.000+00:00", // expiresAt (optional)
+ Map.of("a", "b"), // metadata (optional)
+ List.of(Permission.read(Role.any())), // permissions (optional)
+ false, // purge (optional)
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/java/presences/upsert.md b/docs/examples/java/presences/upsert.md
new file mode 100644
index 00000000..3e1ef96b
--- /dev/null
+++ b/docs/examples/java/presences/upsert.md
@@ -0,0 +1,30 @@
+```java
+import io.appwrite.Client;
+import io.appwrite.coroutines.CoroutineCallback;
+import io.appwrite.Permission;
+import io.appwrite.Role;
+import io.appwrite.services.Presences;
+
+Client client = new Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject(""); // Your project ID
+
+Presences presences = new Presences(client);
+
+presences.upsert(
+ "", // presenceId
+ "", // status
+ List.of(Permission.read(Role.any())), // permissions (optional)
+ "2020-10-15T06:38:00.000+00:00", // expiresAt (optional)
+ Map.of("a", "b"), // metadata (optional)
+ new CoroutineCallback<>((result, error) -> {
+ if (error != null) {
+ error.printStackTrace();
+ return;
+ }
+
+ Log.d("Appwrite", result.toString());
+ })
+);
+
+```
diff --git a/docs/examples/kotlin/advisor/get-insight.md b/docs/examples/kotlin/advisor/get-insight.md
new file mode 100644
index 00000000..6ff14eb9
--- /dev/null
+++ b/docs/examples/kotlin/advisor/get-insight.md
@@ -0,0 +1,16 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Advisor
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val advisor = Advisor(client)
+
+val result = advisor.getInsight(
+ reportId = "",
+ insightId = "",
+)
+```
diff --git a/docs/examples/kotlin/advisor/get-report.md b/docs/examples/kotlin/advisor/get-report.md
new file mode 100644
index 00000000..5ab03055
--- /dev/null
+++ b/docs/examples/kotlin/advisor/get-report.md
@@ -0,0 +1,15 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Advisor
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val advisor = Advisor(client)
+
+val result = advisor.getReport(
+ reportId = "",
+)
+```
diff --git a/docs/examples/kotlin/advisor/list-insights.md b/docs/examples/kotlin/advisor/list-insights.md
new file mode 100644
index 00000000..fb5dfb31
--- /dev/null
+++ b/docs/examples/kotlin/advisor/list-insights.md
@@ -0,0 +1,17 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Advisor
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val advisor = Advisor(client)
+
+val result = advisor.listInsights(
+ reportId = "",
+ queries = listOf(), // (optional)
+ total = false, // (optional)
+)
+```
diff --git a/docs/examples/kotlin/advisor/list-reports.md b/docs/examples/kotlin/advisor/list-reports.md
new file mode 100644
index 00000000..9d230d37
--- /dev/null
+++ b/docs/examples/kotlin/advisor/list-reports.md
@@ -0,0 +1,16 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Advisor
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val advisor = Advisor(client)
+
+val result = advisor.listReports(
+ queries = listOf(), // (optional)
+ total = false, // (optional)
+)
+```
diff --git a/docs/examples/kotlin/presences/delete.md b/docs/examples/kotlin/presences/delete.md
new file mode 100644
index 00000000..d74aae00
--- /dev/null
+++ b/docs/examples/kotlin/presences/delete.md
@@ -0,0 +1,15 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Presences
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val presences = Presences(client)
+
+val result = presences.delete(
+ presenceId = "",
+)
+```
diff --git a/docs/examples/kotlin/presences/get.md b/docs/examples/kotlin/presences/get.md
new file mode 100644
index 00000000..c12a5182
--- /dev/null
+++ b/docs/examples/kotlin/presences/get.md
@@ -0,0 +1,15 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Presences
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val presences = Presences(client)
+
+val result = presences.get(
+ presenceId = "",
+)
+```
diff --git a/docs/examples/kotlin/presences/list.md b/docs/examples/kotlin/presences/list.md
new file mode 100644
index 00000000..6496a3e2
--- /dev/null
+++ b/docs/examples/kotlin/presences/list.md
@@ -0,0 +1,17 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Presences
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val presences = Presences(client)
+
+val result = presences.list(
+ queries = listOf(), // (optional)
+ total = false, // (optional)
+ ttl = 0, // (optional)
+)
+```
diff --git a/docs/examples/kotlin/presences/update.md b/docs/examples/kotlin/presences/update.md
new file mode 100644
index 00000000..c6626913
--- /dev/null
+++ b/docs/examples/kotlin/presences/update.md
@@ -0,0 +1,22 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Presences
+import io.appwrite.Permission
+import io.appwrite.Role
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val presences = Presences(client)
+
+val result = presences.update(
+ presenceId = "",
+ status = "", // (optional)
+ expiresAt = "2020-10-15T06:38:00.000+00:00", // (optional)
+ metadata = mapOf( "a" to "b" ), // (optional)
+ permissions = listOf(Permission.read(Role.any())), // (optional)
+ purge = false, // (optional)
+)
+```
diff --git a/docs/examples/kotlin/presences/upsert.md b/docs/examples/kotlin/presences/upsert.md
new file mode 100644
index 00000000..d868a1dd
--- /dev/null
+++ b/docs/examples/kotlin/presences/upsert.md
@@ -0,0 +1,21 @@
+```kotlin
+import io.appwrite.Client
+import io.appwrite.coroutines.CoroutineCallback
+import io.appwrite.services.Presences
+import io.appwrite.Permission
+import io.appwrite.Role
+
+val client = Client(context)
+ .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint
+ .setProject("") // Your project ID
+
+val presences = Presences(client)
+
+val result = presences.upsert(
+ presenceId = "",
+ status = "",
+ permissions = listOf(Permission.read(Role.any())), // (optional)
+ expiresAt = "2020-10-15T06:38:00.000+00:00", // (optional)
+ metadata = mapOf( "a" to "b" ), // (optional)
+)
+```
diff --git a/example/build.gradle b/example/build.gradle
deleted file mode 100644
index 0ebf8b28..00000000
--- a/example/build.gradle
+++ /dev/null
@@ -1,65 +0,0 @@
-plugins {
- id 'com.android.application'
- id 'kotlin-android'
- id 'kotlin-kapt'
-}
-
-android {
- namespace "io.appwrite.android"
-
- compileSdkVersion 34
-
- defaultConfig {
- applicationId "io.appwrite.android"
- minSdkVersion 21
- targetSdkVersion 34
- versionCode 1
- versionName "1.0"
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
-
- buildFeatures {
- dataBinding true
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
-}
-
-dependencies {
- implementation(project(path: ':library'))
-
- implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
- implementation("androidx.core:core-ktx:1.12.0")
- implementation("androidx.appcompat:appcompat:1.6.1")
- implementation("com.google.android.material:material:1.11.0")
- implementation("androidx.constraintlayout:constraintlayout:2.1.4")
- implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
- implementation("androidx.fragment:fragment-ktx:1.6.2")
- implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
- implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
- implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
- implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
- implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
-
- implementation(platform("com.google.firebase:firebase-bom:32.7.0"))
- implementation("com.google.firebase:firebase-messaging")
-
- testImplementation("junit:junit:4.13.2")
- androidTestImplementation("androidx.test.ext:junit:1.1.5")
- androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
-}
\ No newline at end of file
diff --git a/example/build.gradle.kts b/example/build.gradle.kts
new file mode 100644
index 00000000..2675a918
--- /dev/null
+++ b/example/build.gradle.kts
@@ -0,0 +1,58 @@
+plugins {
+ id("com.android.application")
+}
+
+android {
+ namespace = "io.appwrite.android"
+
+ compileSdk = 36
+
+ defaultConfig {
+ applicationId = "io.appwrite.android"
+ minSdk = 21
+ @Suppress("DEPRECATION")
+ targetSdk = 36
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+}
+
+dependencies {
+ implementation(project(":library"))
+
+ implementation("androidx.core:core-ktx:1.15.0")
+ implementation("androidx.appcompat:appcompat:1.7.0")
+ implementation("com.google.android.material:material:1.12.0")
+ implementation("androidx.constraintlayout:constraintlayout:2.2.0")
+ implementation("androidx.navigation:navigation-fragment-ktx:2.8.5")
+ implementation("androidx.fragment:fragment-ktx:1.8.5")
+ implementation("androidx.navigation:navigation-ui-ktx:2.8.5")
+ implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.7")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2")
+
+ implementation(platform("com.google.firebase:firebase-bom:33.7.0"))
+ implementation("com.google.firebase:firebase-messaging")
+
+ testImplementation("junit:junit:4.13.2")
+ androidTestImplementation("androidx.test.ext:junit:1.2.1")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ebd754f0..2f2958b9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Tue Jun 01 15:55:54 IST 2021
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/library/build.gradle b/library/build.gradle
deleted file mode 100644
index cc21f310..00000000
--- a/library/build.gradle
+++ /dev/null
@@ -1,80 +0,0 @@
-plugins {
- id("com.android.library")
- id("kotlin-android")
-}
-
-ext {
- PUBLISH_GROUP_ID = 'io.appwrite'
- PUBLISH_ARTIFACT_ID = 'sdk-for-android'
- PUBLISH_VERSION = System.getenv('SDK_VERSION')
- POM_URL = 'https://github.com/appwrite/sdk-for-android'
- POM_SCM_URL = 'https://github.com/appwrite/sdk-for-android'
- POM_ISSUE_URL = 'https://github.com/appwrite/sdk-for-android/issues'
- POM_DESCRIPTION = 'Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Android SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)'
- POM_LICENSE_URL = 'https://opensource.org/licenses/GPL-3.0'
- POM_LICENSE_NAME = "GPL-3.0"
- POM_DEVELOPER_ID = 'appwrite'
- POM_DEVELOPER_NAME = 'Appwrite Team'
- POM_DEVELOPER_EMAIL = 'team@appwrite.io'
- GITHUB_SCM_CONNECTION = 'scm:git:git://github.com/appwrite/sdk-for-android.git'
-}
-
-version PUBLISH_VERSION
-
-android {
- namespace PUBLISH_GROUP_ID
-
- compileSdkVersion(34)
-
- buildFeatures {
- buildConfig true
- }
-
- defaultConfig {
- minSdkVersion(21)
- targetSdkVersion(34)
- versionCode = 1
- versionName = "1.0"
- buildConfigField "String", "SDK_VERSION", "\"${PUBLISH_VERSION}\""
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- kotlinOptions {
- jvmTarget = "1.8"
- }
-}
-
-dependencies {
- implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
- api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
- api("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
-
- implementation("com.squareup.okhttp3:okhttp:4.12.0")
- implementation("com.google.code.gson:gson:2.10.1")
-
- implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
- implementation("androidx.lifecycle:lifecycle-common-java8:2.7.0")
- implementation("androidx.appcompat:appcompat:1.6.1")
- implementation("androidx.fragment:fragment-ktx:1.6.2")
- implementation("androidx.activity:activity-ktx:1.8.2")
- implementation("androidx.browser:browser:1.7.0")
- implementation("androidx.core:core-ktx:1.12.0")
-
- testImplementation("junit:junit:4.13.2")
- testImplementation("androidx.test.ext:junit-ktx:1.1.5")
- testImplementation("androidx.test:core-ktx:1.5.0")
- testImplementation("org.robolectric:robolectric:4.11.1")
- testApi("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1")
-}
-
-apply from: "${rootProject.projectDir}/scripts/publish-module.gradle"
diff --git a/library/build.gradle.kts b/library/build.gradle.kts
new file mode 100644
index 00000000..68c3d398
--- /dev/null
+++ b/library/build.gradle.kts
@@ -0,0 +1,143 @@
+import java.util.Properties
+
+plugins {
+ id("com.android.library")
+ `maven-publish`
+ signing
+}
+
+val publishGroupId = "io.appwrite"
+val publishArtifactId = "sdk-for-android"
+val publishVersion: String = System.getenv("SDK_VERSION") ?: "0.0.0"
+val pomUrl = "https://github.com/appwrite/sdk-for-android"
+val pomScmUrl = "https://github.com/appwrite/sdk-for-android"
+val pomDescription = "Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Android SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)"
+val pomLicenseUrl = "https://opensource.org/licenses/GPL-3.0"
+val pomLicenseName = "GPL-3.0"
+val pomDeveloperId = "appwrite"
+val pomDeveloperName = "Appwrite Team"
+val pomDeveloperEmail = "team@appwrite.io"
+val githubScmConnection = "scm:git:git://github.com/appwrite/sdk-for-android.git"
+
+version = publishVersion
+
+val signingKeyId: String = System.getenv("SIGNING_KEY_ID") ?: ""
+val signingPassword: String = System.getenv("SIGNING_PASSWORD") ?: ""
+val signingSecretKeyRingFile: String = System.getenv("SIGNING_SECRET_KEY_RING_FILE") ?: ""
+
+val secretPropsFile = project.rootProject.file("local.properties")
+val localProperties = Properties().apply {
+ if (secretPropsFile.exists()) {
+ secretPropsFile.inputStream().use { load(it) }
+ }
+}
+
+extra["signing.keyId"] = signingKeyId.ifEmpty { localProperties.getProperty("signing.keyId", "") }
+extra["signing.password"] = signingPassword.ifEmpty { localProperties.getProperty("signing.password", "") }
+extra["signing.secretKeyRingFile"] = signingSecretKeyRingFile.ifEmpty { localProperties.getProperty("signing.secretKeyRingFile", "") }
+
+android {
+ namespace = publishGroupId
+
+ compileSdk = 36
+
+ buildFeatures {
+ buildConfig = true
+ }
+
+ defaultConfig {
+ minSdk = 21
+ buildConfigField("String", "SDK_VERSION", "\"$publishVersion\"")
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ }
+ }
+
+ testOptions {
+ unitTests.all {
+ it.systemProperty("robolectric.conscryptMode", "OFF")
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+
+ publishing {
+ singleVariant("release") {
+ withSourcesJar()
+ withJavadocJar()
+ }
+ }
+}
+
+dependencies {
+ api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
+ api("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2")
+
+ api("com.squareup.okhttp3:okhttp:5.3.2")
+ implementation("com.google.code.gson:gson:2.11.0")
+
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
+ implementation("androidx.lifecycle:lifecycle-common-java8:2.8.7")
+ implementation("androidx.appcompat:appcompat:1.7.0")
+ implementation("androidx.fragment:fragment-ktx:1.8.5")
+ implementation("androidx.activity:activity-ktx:1.9.3")
+ implementation("androidx.browser:browser:1.8.0")
+ implementation("androidx.core:core-ktx:1.15.0")
+
+ testImplementation("junit:junit:4.13.2")
+ testImplementation("androidx.test.ext:junit-ktx:1.2.1")
+ testImplementation("androidx.test:core-ktx:1.6.1")
+ testImplementation("org.robolectric:robolectric:4.16.1")
+ testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
+}
+
+afterEvaluate {
+ publishing {
+ publications {
+ register("release") {
+ from(components["release"])
+
+ groupId = publishGroupId
+ artifactId = publishArtifactId
+ version = publishVersion
+
+ pom {
+ name.set(publishArtifactId)
+ description.set(pomDescription)
+ url.set(pomUrl)
+
+ licenses {
+ license {
+ name.set(pomLicenseName)
+ url.set(pomLicenseUrl)
+ }
+ }
+
+ developers {
+ developer {
+ id.set(pomDeveloperId)
+ name.set(pomDeveloperName)
+ email.set(pomDeveloperEmail)
+ }
+ }
+
+ scm {
+ connection.set(githubScmConnection)
+ url.set(pomScmUrl)
+ }
+ }
+ }
+ }
+ }
+
+ signing {
+ sign(publishing.publications)
+ }
+}
diff --git a/library/src/main/java/io/appwrite/Channel.kt b/library/src/main/java/io/appwrite/Channel.kt
index 5c067016..26907f28 100644
--- a/library/src/main/java/io/appwrite/Channel.kt
+++ b/library/src/main/java/io/appwrite/Channel.kt
@@ -14,6 +14,7 @@ public interface _Func
public interface _Execution
public interface _Team
public interface _Membership
+public interface _Presence
public interface _Resolved
// Union type for actionable channels
@@ -81,6 +82,9 @@ class Channel private constructor(
fun membership(id: String): Channel<_Membership> =
Channel(listOf("memberships", normalize(id)))
+ fun presence(id: String): Channel<_Presence> =
+ Channel(listOf("presences", normalize(id)))
+
fun account(): String = "account"
// Global events
@@ -90,6 +94,7 @@ class Channel private constructor(
fun executions(): String = "executions"
fun teams(): String = "teams"
fun memberships(): String = "memberships"
+ fun presences(): String = "presences"
}
}
@@ -251,3 +256,31 @@ fun Channel<_Membership>.update(): Channel<_Resolved> =
@JvmName("deleteMembership")
fun Channel<_Membership>.delete(): Channel<_Resolved> =
this.resolve("delete")
+
+/**
+ * Only available on Channel<_Presence>
+ */
+@JvmName("createPresence")
+fun Channel<_Presence>.create(): Channel<_Resolved> =
+ this.resolve("create")
+
+/**
+ * Only available on Channel<_Presence>
+ */
+@JvmName("upsertPresence")
+fun Channel<_Presence>.upsert(): Channel<_Resolved> =
+ this.resolve("upsert")
+
+/**
+ * Only available on Channel<_Presence>
+ */
+@JvmName("updatePresence")
+fun Channel<_Presence>.update(): Channel<_Resolved> =
+ this.resolve("update")
+
+/**
+ * Only available on Channel<_Presence>
+ */
+@JvmName("deletePresence")
+fun Channel<_Presence>.delete(): Channel<_Resolved> =
+ this.resolve("delete")
diff --git a/library/src/main/java/io/appwrite/Client.kt b/library/src/main/java/io/appwrite/Client.kt
index ccd93894..0fbb47a4 100644
--- a/library/src/main/java/io/appwrite/Client.kt
+++ b/library/src/main/java/io/appwrite/Client.kt
@@ -87,8 +87,8 @@ class Client @JvmOverloads constructor(
"x-sdk-name" to "Android",
"x-sdk-platform" to "client",
"x-sdk-language" to "android",
- "x-sdk-version" to "24.0.0",
- "x-appwrite-response-format" to "1.9.2"
+ "x-sdk-version" to "24.1.0",
+ "x-appwrite-response-format" to "1.9.5"
)
config = mutableMapOf()
@@ -168,6 +168,21 @@ class Client @JvmOverloads constructor(
return this
}
+ /**
+ * Set Cookie
+ *
+ * The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.
+ *
+ * @param {string} cookie
+ *
+ * @return this
+ */
+ fun setCookie(value: String): Client {
+ config["cookie"] = value
+ addHeader("cookie", value)
+ return this
+ }
+
/**
* Set ImpersonateUserId
*
diff --git a/library/src/main/java/io/appwrite/cookies/ListenableCookieJar.kt b/library/src/main/java/io/appwrite/cookies/ListenableCookieJar.kt
index 863eb42e..d88a13a2 100644
--- a/library/src/main/java/io/appwrite/cookies/ListenableCookieJar.kt
+++ b/library/src/main/java/io/appwrite/cookies/ListenableCookieJar.kt
@@ -1,21 +1,25 @@
package io.appwrite.cookies
+import android.util.Log
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
-import okhttp3.internal.cookieToString
-import okhttp3.internal.delimiterOffset
-import okhttp3.internal.platform.Platform
-import okhttp3.internal.trimSubstring
import java.io.IOException
import java.net.CookieHandler
-import java.net.HttpCookie
+import java.text.SimpleDateFormat
import java.util.Collections
+import java.util.Date
+import java.util.Locale
+import java.util.TimeZone
typealias CookieListener = (existing: List, new: List) -> Unit
class ListenableCookieJar(private val cookieHandler: CookieHandler) : CookieJar {
+ private companion object {
+ private const val TAG = "ListenableCookieJar"
+ }
+
private val listeners: MutableMap = mutableMapOf()
fun onSave(key: String, listener: CookieListener) {
@@ -29,16 +33,13 @@ class ListenableCookieJar(private val cookieHandler: CookieHandler) : CookieJar
val cookieStrings = mutableListOf()
for (cookie in cookies) {
- cookieStrings.add(cookieToString(cookie, true))
+ cookieStrings.add(cookieToString(cookie))
}
val multimap = mapOf("Set-Cookie" to cookieStrings)
try {
cookieHandler.put(url.toUri(), multimap)
} catch (e: IOException) {
- Platform.get().log(
- "Saving cookies failed for " + url.resolve("/...")!!,
- Platform.WARN, e
- )
+ Log.w(TAG, "Saving cookies failed for " + url.resolve("/..."), e)
}
}
@@ -46,10 +47,7 @@ class ListenableCookieJar(private val cookieHandler: CookieHandler) : CookieJar
val cookieHeaders = try {
cookieHandler.get(url.toUri(), emptyMap>())
} catch (e: IOException) {
- Platform.get().log(
- "Loading cookies failed for " + url.resolve("/...")!!,
- Platform.WARN, e
- )
+ Log.w(TAG, "Loading cookies failed for " + url.resolve("/..."), e)
return emptyList()
}
@@ -75,10 +73,6 @@ class ListenableCookieJar(private val cookieHandler: CookieHandler) : CookieJar
}
}
- /**
- * Convert a request header to OkHttp's cookies via [HttpCookie]. That extra step handles
- * multiple cookies in a single request header, which [Cookie.parse] doesn't support.
- */
private fun decodeHeaderAsJavaNetCookies(url: HttpUrl, header: String): List {
val result = mutableListOf()
var pos = 0
@@ -93,14 +87,12 @@ class ListenableCookieJar(private val cookieHandler: CookieHandler) : CookieJar
continue
}
- // We have either name=value or just a name.
var value = if (equalsSign < pairEnd) {
header.trimSubstring(equalsSign + 1, pairEnd)
} else {
""
}
- // If the value is "quoted", drop the quotes.
if (value.startsWith("\"") && value.endsWith("\"")) {
value = value.substring(1, value.length - 1)
}
@@ -116,4 +108,55 @@ class ListenableCookieJar(private val cookieHandler: CookieHandler) : CookieJar
}
return result
}
-}
\ No newline at end of file
+
+ private fun cookieToString(cookie: Cookie): String = buildString {
+ append(cookie.name)
+ append('=')
+ append(cookie.value)
+
+ if (cookie.persistent) {
+ if (cookie.expiresAt == Long.MIN_VALUE) {
+ append("; Max-Age=0")
+ } else {
+ append("; Expires=").append(formatHttpDate(cookie.expiresAt))
+ }
+ }
+
+ if (!cookie.hostOnly) {
+ // Leading "." marks the cookie as subdomain-matching per RFC 2965, which java.net.CookieHandler still relies on.
+ append("; Domain=.").append(cookie.domain)
+ }
+
+ append("; Path=").append(cookie.path)
+
+ if (cookie.secure) append("; Secure")
+ if (cookie.httpOnly) append("; HttpOnly")
+ }
+
+ private fun formatHttpDate(epochMillis: Long): String =
+ SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US).apply {
+ timeZone = TimeZone.getTimeZone("GMT")
+ }.format(Date(epochMillis))
+
+ private fun String.delimiterOffset(delimiters: String, startIndex: Int, endIndex: Int): Int {
+ for (i in startIndex until endIndex) {
+ if (this[i] in delimiters) return i
+ }
+ return endIndex
+ }
+
+ private fun String.delimiterOffset(delimiter: Char, startIndex: Int, endIndex: Int): Int {
+ for (i in startIndex until endIndex) {
+ if (this[i] == delimiter) return i
+ }
+ return endIndex
+ }
+
+ private fun String.trimSubstring(startIndex: Int, endIndex: Int): String {
+ var start = startIndex
+ var end = endIndex
+ while (start < end && this[start].isWhitespace()) start++
+ while (end > start && this[end - 1].isWhitespace()) end--
+ return substring(start, end)
+ }
+}
diff --git a/library/src/main/java/io/appwrite/enums/OAuthProvider.kt b/library/src/main/java/io/appwrite/enums/OAuthProvider.kt
index f5f3d39f..b5de3a4c 100644
--- a/library/src/main/java/io/appwrite/enums/OAuthProvider.kt
+++ b/library/src/main/java/io/appwrite/enums/OAuthProvider.kt
@@ -33,12 +33,18 @@ enum class OAuthProvider(val value: String) {
FACEBOOK("facebook"),
@SerializedName("figma")
FIGMA("figma"),
+ @SerializedName("fusionauth")
+ FUSIONAUTH("fusionauth"),
@SerializedName("github")
GITHUB("github"),
@SerializedName("gitlab")
GITLAB("gitlab"),
@SerializedName("google")
GOOGLE("google"),
+ @SerializedName("keycloak")
+ KEYCLOAK("keycloak"),
+ @SerializedName("kick")
+ KICK("kick"),
@SerializedName("linkedin")
LINKEDIN("linkedin"),
@SerializedName("microsoft")
diff --git a/library/src/main/java/io/appwrite/models/Document.kt b/library/src/main/java/io/appwrite/models/Document.kt
index c55e6d26..a192a1dd 100644
--- a/library/src/main/java/io/appwrite/models/Document.kt
+++ b/library/src/main/java/io/appwrite/models/Document.kt
@@ -99,7 +99,7 @@ data class Document(
createdAt = map["\$createdAt"] as String,
updatedAt = map["\$updatedAt"] as String,
permissions = map["\$permissions"] as List,
- data = map["data"]?.jsonCast(to = nestedType) ?: map.jsonCast(to = nestedType)
+ data = map["data"]?.jsonCast(to = nestedType) ?: emptyMap().jsonCast(to = nestedType)
)
}
}
\ No newline at end of file
diff --git a/library/src/main/java/io/appwrite/models/Insight.kt b/library/src/main/java/io/appwrite/models/Insight.kt
new file mode 100644
index 00000000..66c2804a
--- /dev/null
+++ b/library/src/main/java/io/appwrite/models/Insight.kt
@@ -0,0 +1,158 @@
+package io.appwrite.models
+
+import com.google.gson.annotations.SerializedName
+import io.appwrite.extensions.jsonCast
+
+/**
+ * Insight
+ */
+data class Insight(
+ /**
+ * Insight ID.
+ */
+ @SerializedName("\$id")
+ val id: String,
+
+ /**
+ * Insight creation date in ISO 8601 format.
+ */
+ @SerializedName("\$createdAt")
+ val createdAt: String,
+
+ /**
+ * Insight update date in ISO 8601 format.
+ */
+ @SerializedName("\$updatedAt")
+ val updatedAt: String,
+
+ /**
+ * Parent report ID. Insights always belong to a report.
+ */
+ @SerializedName("reportId")
+ val reportId: String,
+
+ /**
+ * Insight type. One of databaseIndex (legacy), tablesDBIndex, documentsDBIndex, vectorsDBIndex, databasePerformance, sitePerformance, siteAccessibility, siteSeo, functionPerformance. The index types are engine-specific so each CTA can pair the right service+method (databases.createIndex, tablesDB.createIndex, documentsDB.createIndex, or vectorsDB.createIndex).
+ */
+ @SerializedName("type")
+ val type: String,
+
+ /**
+ * Insight severity. One of info, warning, critical.
+ */
+ @SerializedName("severity")
+ val severity: String,
+
+ /**
+ * Insight status. One of active, dismissed.
+ */
+ @SerializedName("status")
+ val status: String,
+
+ /**
+ * Type of the resource the insight is about. Plural noun, e.g. databases, sites, functions.
+ */
+ @SerializedName("resourceType")
+ val resourceType: String,
+
+ /**
+ * ID of the resource the insight is about.
+ */
+ @SerializedName("resourceId")
+ val resourceId: String,
+
+ /**
+ * Plural noun for the parent resource that contains the insight's resource, e.g. an insight about a column index on a table → resourceType=indexes, parentResourceType=tables. Empty when the resource has no parent.
+ */
+ @SerializedName("parentResourceType")
+ val parentResourceType: String,
+
+ /**
+ * ID of the parent resource. Empty when the resource has no parent.
+ */
+ @SerializedName("parentResourceId")
+ val parentResourceId: String,
+
+ /**
+ * Insight title.
+ */
+ @SerializedName("title")
+ val title: String,
+
+ /**
+ * Short markdown summary describing the insight.
+ */
+ @SerializedName("summary")
+ val summary: String,
+
+ /**
+ * List of call-to-action buttons attached to this insight.
+ */
+ @SerializedName("ctas")
+ val ctas: List,
+
+ /**
+ * Time the insight was analyzed in ISO 8601 format.
+ */
+ @SerializedName("analyzedAt")
+ var analyzedAt: String?,
+
+ /**
+ * Time the insight was dismissed in ISO 8601 format. Empty when not dismissed.
+ */
+ @SerializedName("dismissedAt")
+ var dismissedAt: String?,
+
+ /**
+ * User ID that dismissed the insight. Empty when not dismissed.
+ */
+ @SerializedName("dismissedBy")
+ var dismissedBy: String?,
+
+) {
+ fun toMap(): Map = mapOf(
+ "\$id" to id as Any,
+ "\$createdAt" to createdAt as Any,
+ "\$updatedAt" to updatedAt as Any,
+ "reportId" to reportId as Any,
+ "type" to type as Any,
+ "severity" to severity as Any,
+ "status" to status as Any,
+ "resourceType" to resourceType as Any,
+ "resourceId" to resourceId as Any,
+ "parentResourceType" to parentResourceType as Any,
+ "parentResourceId" to parentResourceId as Any,
+ "title" to title as Any,
+ "summary" to summary as Any,
+ "ctas" to ctas.map { it.toMap() } as Any,
+ "analyzedAt" to analyzedAt as Any,
+ "dismissedAt" to dismissedAt as Any,
+ "dismissedBy" to dismissedBy as Any,
+ )
+
+ companion object {
+
+ @Suppress("UNCHECKED_CAST")
+ fun from(
+ map: Map,
+ ) = Insight(
+ id = map["\$id"] as String,
+ createdAt = map["\$createdAt"] as String,
+ updatedAt = map["\$updatedAt"] as String,
+ reportId = map["reportId"] as String,
+ type = map["type"] as String,
+ severity = map["severity"] as String,
+ status = map["status"] as String,
+ resourceType = map["resourceType"] as String,
+ resourceId = map["resourceId"] as String,
+ parentResourceType = map["parentResourceType"] as String,
+ parentResourceId = map["parentResourceId"] as String,
+ title = map["title"] as String,
+ summary = map["summary"] as String,
+ ctas = (map["ctas"] as List