Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
bot-storage-mongo.24.9.4.source-code.UserTimelineCol.kt Maven / Gradle / Ivy
/*
* Copyright (C) 2017/2021 e-voyageurs technologies
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ai.tock.bot.mongo
import ai.tock.bot.admin.user.UserAnalytics
import ai.tock.bot.admin.user.UserReport
import ai.tock.bot.engine.action.SendAttachment
import ai.tock.bot.engine.action.SendChoice
import ai.tock.bot.engine.action.SendLocation
import ai.tock.bot.engine.action.SendSentence
import ai.tock.bot.engine.user.PlayerId
import ai.tock.bot.engine.user.TimeBoxedFlag
import ai.tock.bot.engine.user.UserPreferences
import ai.tock.bot.engine.user.UserState
import ai.tock.bot.engine.user.UserTimeline
import ai.tock.shared.defaultLocale
import ai.tock.shared.defaultZoneId
import ai.tock.shared.security.TockObfuscatorService.obfuscate
import ai.tock.shared.security.decrypt
import ai.tock.shared.security.encrypt
import ai.tock.shared.security.encryptionEnabled
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.JsonToken
import com.fasterxml.jackson.core.TreeNode
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import org.litote.jackson.data.JacksonData
import org.litote.kmongo.Data
import org.litote.kmongo.Id
import org.litote.kmongo.toId
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.Locale
@Data(internal = true)
@JacksonData(internal = true)
internal data class UserTimelineCol(
val _id: Id,
val playerId: PlayerId,
val userPreferences: UserPreferencesWrapper,
val userState: UserStateWrapper,
val temporaryIds: MutableSet = mutableSetOf(),
val applicationIds: MutableSet = mutableSetOf(),
var lastActionText: String? = null,
val lastUpdateDate: Instant = Instant.now(),
var lastUserActionDate: Instant = lastUpdateDate,
val namespace: String? = null,
val creationDate: Instant = Instant.now()
) {
constructor(timelineId: String, namespace: String, newTimeline: UserTimeline, oldTimeline: UserTimelineCol?) : this(
timelineId.toId(),
newTimeline.playerId,
UserPreferencesWrapper(newTimeline.userPreferences),
UserStateWrapper(newTimeline.userState),
newTimeline.temporaryIds,
namespace = namespace
) {
// register last action
newTimeline.lastUserAction
?.let {
lastUserActionDate = it.date
lastActionText = when (it) {
is SendSentence -> obfuscate(it.stringText, it.nlpStats?.obfuscatedRanges() ?: emptyList())
is SendChoice -> "(click) ${it.intentName}"
is SendAttachment -> "(send) ${it.url}"
is SendLocation -> "(send user location)"
else -> null
}
}
// register application id
oldTimeline?.let {
applicationIds.addAll(it.applicationIds)
}
newTimeline.lastAction?.also {
applicationIds.add(it.applicationId)
}
}
fun toUserTimeline(): UserTimeline {
return UserTimeline(
playerId,
userPreferences.toUserPreferences(),
userState.toUserState(),
temporaryIds = temporaryIds
)
}
fun toUserReport(): UserReport {
return UserReport(
playerId,
applicationIds,
userPreferences.toUserPreferences(),
userState.toUserState(),
lastUpdateDate,
lastActionText,
lastUserActionDate
)
}
fun toUserAnalytics(): UserAnalytics {
val zoneId = defaultZoneId
return UserAnalytics(
playerId,
applicationIds,
LocalDateTime.ofInstant(lastUserActionDate, zoneId).toLocalDate(),
LocalDateTime.ofInstant(lastUserActionDate, zoneId)
)
}
@Data(internal = true)
@JacksonData(internal = true)
data class UserPreferencesWrapper(
val firstName: String? = null,
val lastName: String? = null,
val email: String? = null,
val timezone: ZoneId = defaultZoneId,
val locale: Locale = defaultLocale,
val picture: String? = null,
val gender: String? = null,
val initialLocale: Locale = locale,
/**
* Is it a test user?
*/
val test: Boolean = false,
val encrypted: Boolean = false
) {
constructor(pref: UserPreferences) : this(
pref.firstName?.let { if (encryptionEnabled) encrypt(it) else it },
pref.lastName?.let { if (encryptionEnabled) encrypt(it) else it },
pref.email?.let { if (encryptionEnabled) encrypt(it) else it },
pref.timezone,
pref.locale,
pref.picture?.let { if (encryptionEnabled) encrypt(it) else it },
pref.gender?.let { if (encryptionEnabled) encrypt(it) else it },
pref.initialLocale,
pref.test,
encryptionEnabled
)
fun toUserPreferences(): UserPreferences {
return UserPreferences(
firstName?.let { if (encrypted) decrypt(it) else it },
lastName?.let { if (encrypted) decrypt(it) else it },
email?.let { if (encrypted) decrypt(it) else it },
timezone,
locale,
picture?.let { if (encrypted) decrypt(it) else it },
gender?.let { if (encrypted) decrypt(it) else it },
test,
initialLocale
)
}
}
@Data(internal = true)
class UserStateWrapper(
val creationDate: Instant = Instant.now(),
val lastUpdateDate: Instant = creationDate,
@JsonDeserialize(using = FlagsDeserializer::class)
val flags: Map
) {
constructor(state: UserState) :
this(
state.creationDate,
Instant.now(),
state.flags.mapValues {
TimeBoxedFlagWrapper(
it.value,
MongoBotConfiguration.hasToEncryptFlag(it.key)
)
}
)
fun toUserState(): UserState {
return UserState(
creationDate,
flags.mapValues { it.value.toTimeBoxedFlag() }.toMutableMap()
)
}
}
data class TimeBoxedFlagWrapper(
val encrypted: Boolean = false,
val value: String,
val expirationDate: Instant? = Instant.now()
) {
constructor(flag: TimeBoxedFlag, doEncrypt: Boolean) : this(
doEncrypt,
if (doEncrypt) encrypt(flag.value) else flag.value,
flag.expirationDate
)
fun toTimeBoxedFlag(): TimeBoxedFlag = TimeBoxedFlag(
decryptValue(),
expirationDate
)
fun decryptValue(): String {
return if (encrypted) {
decrypt(value)
} else {
value
}
}
}
class FlagsDeserializer : JsonDeserializer>() {
companion object {
val reference = object : TypeReference>() {}
}
override fun deserialize(jp: JsonParser, context: DeserializationContext): Map {
val mapper = jp.getCodec()
return if (jp.getCurrentToken() == JsonToken.START_OBJECT) {
mapper.readValue(jp, reference)
} else {
// consume this stream
mapper.readTree(jp)
emptyMap()
}
}
}
}