diff --git a/.travis.yml b/.travis.yml index 5a2435c..21a27c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ cache: - $HOME/.gradle/wrapper/ jdk: - - oraclejdk8 + - openjdk10 after_success: - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/alexa-plugin/build.gradle b/alexa-plugin/build.gradle index 4462813..865f077 100644 --- a/alexa-plugin/build.gradle +++ b/alexa-plugin/build.gradle @@ -8,7 +8,7 @@ description 'The Alexa plugin for Dialog to write voice applications for Dialogf dependencies { implementation project(":core") implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation "com.amazon.alexa:ask-sdk-core:2.17.0" + implementation "com.amazon.alexa:ask-sdk-core:2.19.0" } dokka { diff --git a/alexa-spring-plugin/build.gradle b/alexa-spring-plugin/build.gradle index e67fdd4..db17552 100644 --- a/alexa-spring-plugin/build.gradle +++ b/alexa-spring-plugin/build.gradle @@ -22,8 +22,8 @@ dependencies { implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' implementation 'org.jetbrains.kotlin:kotlin-reflect' - implementation 'org.springframework:spring-context:5.1.4.RELEASE' - implementation 'com.amazon.alexa:ask-sdk-core:2.11.2' + implementation 'org.springframework:spring-context:5.1.8.RELEASE' + implementation 'com.amazon.alexa:ask-sdk-core:2.19.0' } task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) { diff --git a/core/build.gradle b/core/build.gradle index 3a8f66a..ca33924 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -7,6 +7,7 @@ description 'Dialog is a Dialogflow v2 API implementation written in Kotlin. Wit dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + implementation 'com.google.code.gson:gson:2.8.5' } task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) { diff --git a/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowHandler.kt b/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowHandler.kt index 0b0f7b8..077a955 100644 --- a/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowHandler.kt +++ b/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowHandler.kt @@ -1,14 +1,15 @@ package org.rewedigital.dialog.handler -import org.rewedigital.dialog.extensions.getSelectedOption -import org.rewedigital.dialog.extensions.hasSurfaceCapability -import org.rewedigital.dialog.extensions.permissionGranted -import org.rewedigital.dialog.extensions.signInStatus +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import org.rewedigital.dialog.extensions.* import org.rewedigital.dialog.model.dialogflow.DialogflowParams import org.rewedigital.dialog.model.dialogflow.OutputContext import org.rewedigital.dialog.model.dialogflow.WebhookRequest import org.rewedigital.dialog.model.google.Conversation import org.rewedigital.dialog.model.google.SurfaceCapabilities +import java.util.* +import kotlin.collections.HashMap /** * Wrapper of [WebhookRequest] which provides utility functions for easier context access and other parameters. @@ -19,12 +20,22 @@ class DialogflowHandler(private val webhookRequest: WebhookRequest) { /** * Holds context related information. */ - val context: DialogflowHandler.ContextWrapper = - DialogflowHandler.ContextWrapper(webhookRequest.queryResult?.outputContexts.orEmpty().map { + val context: ContextWrapper = + ContextWrapper(webhookRequest.queryResult?.outputContexts.orEmpty().map { // clone the list and remove the session prefix it.copy(name = it.name?.replace("${webhookRequest.session.orEmpty()}/contexts/", "")) }.toMutableList(), webhookRequest.session.orEmpty()) + /** + * The stored user data aka user storage. + * @see https://developers.google.com/actions/assistant/save-data#json + */ + val userData: MutableMap = run { + val userData = webhookRequest.originalDetectIntentRequest?.payload?.user?.userStorage + ?: return@run mutableMapOf() + fromJson(userData).toMutableMap() + } + /** * The action name defined in Dialogflow. */ @@ -52,9 +63,22 @@ class DialogflowHandler(private val webhookRequest: WebhookRequest) { /** * An unique identifier of the users google account. */ - val userId: String? - get() = webhookRequest.originalDetectIntentRequest?.payload?.user?.userId - ?: webhookRequest.originalDetectIntentRequest?.payload?.user?.idToken + val userId: String + get() { + return if (userData.containsKey("userId")) { + userData["userId"] as String + } else { + val oldUserId = webhookRequest.originalDetectIntentRequest?.payload?.user?.userId + if (oldUserId.isNullOrEmpty()) { + val newUserId = UUID.randomUUID().toString() + userData["userId"] = newUserId + newUserId + } else { + userData["userId"] = oldUserId + oldUserId + } + } + } /** * The unique identifier of detectIntent request session. @@ -182,6 +206,26 @@ class DialogflowHandler(private val webhookRequest: WebhookRequest) { context[name, key] = value } + private fun fromJson(serializedValue: String?): Map { + if (serializedValue != null && serializedValue.isNotEmpty()) { + val gson = Gson() + try { + val map: Map = gson.fromJson( + serializedValue, + object : TypeToken>() {}.type + ) + // NOTE: The format of the opaque string is: + // keyValueData: {key:value; key:value; } + if (map["data"] != null) { + return map["data"] as Map + } + } catch (e: Exception) { + println(e.message) + } + } + return HashMap() + } + class ContextWrapper( private val context: MutableList, private val session: String diff --git a/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowResponseBuilder.kt b/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowResponseBuilder.kt index fe1abba..1e734bc 100644 --- a/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowResponseBuilder.kt +++ b/core/src/main/kotlin/org/rewedigital/dialog/handler/DialogflowResponseBuilder.kt @@ -1,5 +1,6 @@ package org.rewedigital.dialog.handler +import com.google.gson.Gson import org.rewedigital.dialog.extensions.validate import org.rewedigital.dialog.factories.SystemIntentFactory import org.rewedigital.dialog.model.dialogflow.* @@ -11,7 +12,11 @@ class DialogflowResponseBuilder(private val dialogflowHandler: DialogflowHandler private val response = WebhookResponse() private fun WebhookResponse.getOrCreatePayload() = - payload ?: Payload(google = GooglePayload(richResponse = RichResponse())).also { newPayload -> + payload ?: Payload( + google = GooglePayload( + richResponse = RichResponse() + ) + ).also { newPayload -> payload = newPayload } @@ -262,6 +267,16 @@ class DialogflowResponseBuilder(private val dialogflowHandler: DialogflowHandler .apply { source = "Webhook" outputContexts = dialogflowHandler.getContextList().toMutableList() + getOrCreatePayload().google?.userStorage = run { + val dataMap = HashMap() + dataMap["data"] = dialogflowHandler.userData + Gson().toJson(dataMap) + } + + // Remove RichResponse if there are no items in it + if (payload?.google?.richResponse?.items?.isEmpty() == true) { + payload?.google?.richResponse = null + } } .validate() } \ No newline at end of file diff --git a/core/src/main/kotlin/org/rewedigital/dialog/model/google/User.kt b/core/src/main/kotlin/org/rewedigital/dialog/model/google/User.kt index bba3dc6..0d838e1 100644 --- a/core/src/main/kotlin/org/rewedigital/dialog/model/google/User.kt +++ b/core/src/main/kotlin/org/rewedigital/dialog/model/google/User.kt @@ -9,7 +9,7 @@ data class User( val permissions: List?, val locale: String?, val lastSeen: String?, - val userStorage: String? + var userStorage: String? ) { data class Profile( val displayName: String?, diff --git a/core/src/main/kotlin/org/rewedigital/dialog/model/google/UserStorage.kt b/core/src/main/kotlin/org/rewedigital/dialog/model/google/UserStorage.kt deleted file mode 100644 index a21bc6a..0000000 --- a/core/src/main/kotlin/org/rewedigital/dialog/model/google/UserStorage.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.rewedigital.dialog.model.google - -import org.rewedigital.dialog.model.dialogflow.DialogflowParams - - -data class UserStorage(val data: DialogflowParams) \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 8dde0c3..0131776 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ rootProject.name = 'dialog' include 'core' -include 'ssml' +include 'ssml-builder' include 'ssml-plugin' include 'spring-sample' include 'spring-plugin' diff --git a/spring-plugin/build.gradle b/spring-plugin/build.gradle index 07301e6..f9266e4 100644 --- a/spring-plugin/build.gradle +++ b/spring-plugin/build.gradle @@ -20,7 +20,7 @@ dependencies { implementation 'org.jetbrains.kotlin:kotlin-reflect' implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - implementation 'org.springframework:spring-context:5.1.6.RELEASE' + implementation 'org.springframework:spring-context:5.1.8.RELEASE' } dokka { diff --git a/spring-sample/build.gradle b/spring-sample/build.gradle index 2cea9ca..95f7145 100644 --- a/spring-sample/build.gradle +++ b/spring-sample/build.gradle @@ -3,7 +3,7 @@ version '1.0.0-SNAPSHOT' buildscript { ext { - springBootVersion = '2.1.4.RELEASE' + springBootVersion = '2.1.6.RELEASE' } repositories { jcenter() @@ -35,10 +35,10 @@ compileTestKotlin { } dependencies { - def askSdkVersion = '2.17.0' + def askSdkVersion = '2.19.0' implementation project(':core') - implementation project(':ssml') + implementation project(':ssml-builder') implementation project(':ssml-plugin') implementation project(':spring-plugin') implementation project(':konversation-plugin') diff --git a/ssml/build.gradle b/ssml-builder/build.gradle similarity index 100% rename from ssml/build.gradle rename to ssml-builder/build.gradle diff --git a/ssml/src/main/kotlin/org/rewedigital/dialog/ssml/AmazonEffect.kt b/ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/AmazonEffect.kt similarity index 100% rename from ssml/src/main/kotlin/org/rewedigital/dialog/ssml/AmazonEffect.kt rename to ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/AmazonEffect.kt diff --git a/ssml/src/main/kotlin/org/rewedigital/dialog/ssml/Emphasis.kt b/ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/Emphasis.kt similarity index 100% rename from ssml/src/main/kotlin/org/rewedigital/dialog/ssml/Emphasis.kt rename to ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/Emphasis.kt diff --git a/ssml/src/main/kotlin/org/rewedigital/dialog/ssml/InterpretAs.kt b/ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/InterpretAs.kt similarity index 100% rename from ssml/src/main/kotlin/org/rewedigital/dialog/ssml/InterpretAs.kt rename to ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/InterpretAs.kt diff --git a/ssml/src/main/kotlin/org/rewedigital/dialog/ssml/SsmlBuilder.kt b/ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/SsmlBuilder.kt similarity index 100% rename from ssml/src/main/kotlin/org/rewedigital/dialog/ssml/SsmlBuilder.kt rename to ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/SsmlBuilder.kt diff --git a/ssml/src/main/kotlin/org/rewedigital/dialog/ssml/Strength.kt b/ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/Strength.kt similarity index 100% rename from ssml/src/main/kotlin/org/rewedigital/dialog/ssml/Strength.kt rename to ssml-builder/src/main/kotlin/org/rewedigital/dialog/ssml/Strength.kt diff --git a/ssml/src/main/kotlin/org/rewedigital/dialog/utils/RandomUtils.kt b/ssml-builder/src/main/kotlin/org/rewedigital/dialog/utils/RandomUtils.kt similarity index 100% rename from ssml/src/main/kotlin/org/rewedigital/dialog/utils/RandomUtils.kt rename to ssml-builder/src/main/kotlin/org/rewedigital/dialog/utils/RandomUtils.kt diff --git a/ssml-plugin/build.gradle b/ssml-plugin/build.gradle index 5070eab..dad1188 100644 --- a/ssml-plugin/build.gradle +++ b/ssml-plugin/build.gradle @@ -10,7 +10,7 @@ apply from: '../docu.gradle' dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" implementation project(':core') - implementation project(':ssml') + implementation project(':ssml-builder') } dokka {