diff --git a/build.gradle b/build.gradle index efc2af0..487c4db 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ repositories { maven { url "https://maven.dcm4che.org" } + jcenter() } dependencies { @@ -72,7 +73,7 @@ dependencies { // WebJars Locator implementation 'org.webjars:webjars-locator:0.46' - // + // implementation ("org.webjars.bower:bootstrap:5.2.2") implementation ("org.webjars.bower:demo-console:1.5.1") implementation ("org.webjars.bower:draggabilly:2.1.0") @@ -80,7 +81,7 @@ dependencies { implementation ("org.webjars.bower:jquery:3.6.1") implementation ("org.webjars.bower:jsnlog.js:2.20.1") implementation ("org.webjars.bower:webrtc-adapter:7.4.0") - + implementation("org.kurento:kurento-commons:7.1.0") implementation("org.kurento:kurento-client:7.1.0") implementation("org.kurento:kurento-utils-js:7.1.0") @@ -93,6 +94,9 @@ dependencies { testImplementation 'org.testcontainers:postgresql:1.19.7' + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation 'com.google.firebase:firebase-admin:9.2.0' + } tasks.named('test') { diff --git a/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Reminder.kt b/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Reminder.kt index a2811a6..a92524f 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Reminder.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Reminder.kt @@ -16,6 +16,8 @@ data class Reminder( ): BaseModel data class ReminderItem( - val remindAt: LocalDateTime?, + val remindAt: String?, val description: String? -) \ No newline at end of file +){ + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Todos.kt b/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Todos.kt index cd18322..28bafaa 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Todos.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/assistant/model/Todos.kt @@ -18,6 +18,6 @@ data class Todos( data class Todo( val executor: String?, val description: String?, - val dueDate: LocalDateTime?, + val dueDate: String?, val context: String? ) \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/component/state/DefaultStateApi.kt b/src/main/kotlin/io/openfuture/openmessenger/component/state/DefaultStateApi.kt new file mode 100644 index 0000000..5578af1 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/component/state/DefaultStateApi.kt @@ -0,0 +1,40 @@ +package io.openfuture.openmessenger.component.state + +import io.openfuture.openmessenger.repository.entity.BlockchainType +import io.openfuture.openmessenger.service.dto.StateWalletDto +import org.springframework.http.MediaType +import org.springframework.stereotype.Component +import org.springframework.web.reactive.function.BodyInserters +import org.springframework.web.reactive.function.client.WebClient + + +@Component +class DefaultStateApi( + private val stateWebClient: WebClient +) : StateApi { + + override fun createWallet( + address: String, + webHook: String, + blockchain: BlockchainType, + applicationId: String + ): StateWalletDto? { + val request = CreateStateWalletRequest(address, applicationId, blockchain.getValue(), webHook) + println("State save request $request") + return stateWebClient + .post() + .uri("http://localhost:8545/api/wallets/single") + .accept(MediaType.APPLICATION_JSON) + .body(BodyInserters.fromValue(request)) + .retrieve() + .bodyToMono(StateWalletDto::class.java) + .block() + } + + data class CreateStateWalletRequest( + val address: String, + val applicationId: String, + val blockchain: String, + val webhook: String + ) +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/component/state/StateApi.kt b/src/main/kotlin/io/openfuture/openmessenger/component/state/StateApi.kt new file mode 100644 index 0000000..ce28d15 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/component/state/StateApi.kt @@ -0,0 +1,8 @@ +package io.openfuture.openmessenger.component.state + +import io.openfuture.openmessenger.repository.entity.BlockchainType +import io.openfuture.openmessenger.service.dto.StateWalletDto + +interface StateApi { + fun createWallet(address: String, webHook: String, blockchain: BlockchainType, applicationId: String): StateWalletDto? +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/configuration/SecurityConfig.kt b/src/main/kotlin/io/openfuture/openmessenger/configuration/SecurityConfig.kt index 7fa69e9..f93f2d7 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/configuration/SecurityConfig.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/configuration/SecurityConfig.kt @@ -2,7 +2,6 @@ package io.openfuture.openmessenger.configuration import io.openfuture.openmessenger.security.AwsCognitoTokenFilter import io.openfuture.openmessenger.security.CognitoAuthenticationProvider -import jakarta.servlet.http.HttpServletRequest import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.security.config.Customizer @@ -14,9 +13,6 @@ import org.springframework.security.config.annotation.web.configurers.SessionMan import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter -import org.springframework.web.cors.CorsConfiguration -import org.springframework.web.cors.CorsConfigurationSource -import org.springframework.web.cors.UrlBasedCorsConfigurationSource @Configuration @EnableWebSecurity @@ -36,6 +32,8 @@ class SecurityConfig( .authorizeHttpRequests { it.requestMatchers("/api/v1/public/login").permitAll() it.requestMatchers("/api/v1/public/signup").permitAll() + it.requestMatchers("/api/v1/refreshToken").permitAll() + it.requestMatchers("/api/v1/wallets/webhook").permitAll() it.requestMatchers("/api/v1/attachments/download/**").permitAll() it.requestMatchers("/*").permitAll() it.requestMatchers("/webjars/**").permitAll() @@ -52,7 +50,9 @@ class SecurityConfig( "/api/v1/public/login", "/api/v1/public/signup", "/api/v1/attachments/download/**", - listOf("/*", "/webjars/**", "/js/*", "/img/*", "/css/*", "/video/*") + listOf("/*", "/webjars/**", "/js/*", "/img/*", "/css/*", "/video/*"), + "/api/v1/refreshToken", + "/api/v1/wallets/webhook" ), UsernamePasswordAuthenticationFilter::class.java ) diff --git a/src/main/kotlin/io/openfuture/openmessenger/configuration/StateConfig.kt b/src/main/kotlin/io/openfuture/openmessenger/configuration/StateConfig.kt new file mode 100644 index 0000000..1f1ea27 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/configuration/StateConfig.kt @@ -0,0 +1,18 @@ +package io.openfuture.openmessenger.configuration + +import io.openfuture.openmessenger.configuration.property.StateProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.reactive.function.client.WebClient + + +@Configuration +class StateConfig { + + @Bean + fun stateClient(stateProperties: StateProperties): WebClient = + WebClient.builder() + .baseUrl(stateProperties.baseUrl!!) + .build() + +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/configuration/property/StateProperties.kt b/src/main/kotlin/io/openfuture/openmessenger/configuration/property/StateProperties.kt new file mode 100644 index 0000000..a340b36 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/configuration/property/StateProperties.kt @@ -0,0 +1,12 @@ +package io.openfuture.openmessenger.configuration.property + +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.stereotype.Component +import org.springframework.validation.annotation.Validated +import javax.validation.constraints.NotBlank +import javax.validation.constraints.NotNull + +@ConfigurationProperties(prefix = "state") +@Validated +@Component +data class StateProperties(@field:NotNull @field:NotBlank var baseUrl: String?) diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/BlockchainContractRepository.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/BlockchainContractRepository.kt new file mode 100644 index 0000000..ff69514 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/BlockchainContractRepository.kt @@ -0,0 +1,15 @@ +package io.openfuture.openmessenger.repository + +import io.openfuture.openmessenger.repository.entity.BlockchainContractEntity +import io.openfuture.openmessenger.repository.entity.BlockchainType +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface BlockchainContractRepository : JpaRepository { + @Query("SELECT t from BlockchainContractEntity t where t.blockchain = :blockchain and t.isTest = :isTest") + fun findFirstByBlockchain(blockchain: BlockchainType, isTest: Boolean) : BlockchainContractEntity? + + @Query("SELECT t from BlockchainContractEntity t where t.isTest = :isTest") + fun findAllByIsTest(isTest: Boolean) : List + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/TaskRepository.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/TaskRepository.kt new file mode 100644 index 0000000..0859918 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/TaskRepository.kt @@ -0,0 +1,11 @@ +package io.openfuture.openmessenger.repository + +import io.openfuture.openmessenger.repository.entity.TaskEntity +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface TaskRepository : JpaRepository { + @Query("SELECT t from TaskEntity t where t.assignee = :emailAddress or t.assignor =:emailAddress ") + fun findAllByAssigneeOrAssignor(emailAddress: String) : List + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/UserFirebaseTokenRepository.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/UserFirebaseTokenRepository.kt new file mode 100644 index 0000000..fd86d37 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/UserFirebaseTokenRepository.kt @@ -0,0 +1,10 @@ +package io.openfuture.openmessenger.repository + +import io.openfuture.openmessenger.repository.entity.UserFireBaseToken +import org.springframework.data.jpa.repository.JpaRepository +import java.util.Optional + +interface UserFirebaseTokenRepository : JpaRepository { + fun findAllByUserId(userId: String): List + fun findFirstByUserId(userId: String): Optional +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/WalletRepository.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/WalletRepository.kt new file mode 100644 index 0000000..bc1dbce --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/WalletRepository.kt @@ -0,0 +1,14 @@ +package io.openfuture.openmessenger.repository + +import io.openfuture.openmessenger.repository.entity.WalletEntity +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface WalletRepository : JpaRepository { + @Query("SELECT t from WalletEntity t where t.userId =:userId ") + fun findAllByUserId(userId: String) : List + + @Query("SELECT t from WalletEntity t where lower(t.address) =:address ") + fun findFirstByAddress(address: String) : WalletEntity? + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/entity/BlockchainContractEntity.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/BlockchainContractEntity.kt new file mode 100644 index 0000000..4eb6c20 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/BlockchainContractEntity.kt @@ -0,0 +1,38 @@ +package io.openfuture.openmessenger.repository.entity + +import jakarta.persistence.* +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalDateTime.now + +@Entity +@Table(name = "blockchain_contracts") +class BlockchainContractEntity() { + constructor( + contractAddress: String, + contractName: String, + decimal: Int, + blockchain: BlockchainType, + isTest: Boolean + ): this() { + this.contractName = contractName + this.contractAddress = contractAddress + this.blockchain = blockchain + this.isTest = isTest + this.decimal = decimal + this.createdAt = now() + this.updatedAt = now() + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + var createdAt: LocalDateTime? = now() + var updatedAt: LocalDateTime? = now() + var isTest: Boolean = false + @Enumerated(EnumType.STRING) + var blockchain: BlockchainType = BlockchainType.BTC + var contractAddress: String? = null + var contractName: String? = null + var decimal: Int? = 6 +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/entity/BlockchainType.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/BlockchainType.kt new file mode 100644 index 0000000..cb8b41f --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/BlockchainType.kt @@ -0,0 +1,21 @@ +package io.openfuture.openmessenger.repository.entity + +import io.openfuture.openmessenger.repository.entity.base.Dictionary + + +enum class BlockchainType( + private val id: Int, + private val value: String +) : Dictionary { + + ETH(1, "ETH"), + BTC(2, "BTC"), + BNB(3, "BNB"), + TRX(4, "TRX") + ; + + override fun getId(): Int = id + + fun getValue(): String = value + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/entity/TaskEntity.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/TaskEntity.kt new file mode 100644 index 0000000..cc6474e --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/TaskEntity.kt @@ -0,0 +1,37 @@ +package io.openfuture.openmessenger.repository.entity + +import jakarta.persistence.* +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalDateTime.now + +@Entity +@Table(name = "open_tasks") +class TaskEntity() { + constructor( + assignor: String?, + assignee: String?, + taskTitle: String?, + taskDescription: String?, + taskDate: LocalDate? + ): this() { + this.assignee = assignee + this.assignor = assignor + this.taskTitle = taskTitle + this.taskDescription = taskDescription + this.taskDate = taskDate + this.createdAt = now() + this.updatedAt = now() + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + var createdAt: LocalDateTime? = now() + var updatedAt: LocalDateTime? = now() + var assignor: String? = null + var assignee: String? = null + var taskTitle: String? = null + var taskDescription: String? = null + var taskDate: LocalDate? = LocalDate.now() +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/entity/UserFireBaseToken.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/UserFireBaseToken.kt new file mode 100644 index 0000000..255019b --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/UserFireBaseToken.kt @@ -0,0 +1,27 @@ +package io.openfuture.openmessenger.repository.entity + +import jakarta.persistence.* +import java.time.LocalDateTime + +@Entity +@Table(name = "user_firebase_tokens") +class UserFireBaseToken() { + constructor( + userId: String, + token: String + ) : this() { + this.userId = userId + this.firebaseToken = token + this.createdAt = LocalDateTime.now() + this.updatedAt = LocalDateTime.now() + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + var createdAt: LocalDateTime = LocalDateTime.now() + var updatedAt: LocalDateTime = LocalDateTime.now() + var userId: String? = null + var firebaseToken: String? = null + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/entity/WalletEntity.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/WalletEntity.kt new file mode 100644 index 0000000..c3b92be --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/WalletEntity.kt @@ -0,0 +1,33 @@ +package io.openfuture.openmessenger.repository.entity + +import jakarta.persistence.* +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalDateTime.now + +@Entity +@Table(name = "open_wallets") +class WalletEntity() { + constructor( + address: String, + blockchainType: BlockchainType, + userId: String + ): this() { + this.address = address + this.userId = userId + this.blockchainType = blockchainType + this.createdAt = now() + this.updatedAt = now() + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + var createdAt: LocalDateTime? = now() + var updatedAt: LocalDateTime? = now() + var address: String? = null + @Enumerated(EnumType.STRING) + var blockchainType: BlockchainType = BlockchainType.BTC + var balance: String? = null + var userId: String? = null +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/repository/entity/base/Dictionary.kt b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/base/Dictionary.kt new file mode 100644 index 0000000..78d592a --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/repository/entity/base/Dictionary.kt @@ -0,0 +1,7 @@ +package io.openfuture.openmessenger.repository.entity.base + +interface Dictionary { + + fun getId(): Int + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/security/AwsCognitoTokenFilter.kt b/src/main/kotlin/io/openfuture/openmessenger/security/AwsCognitoTokenFilter.kt index 54b8bf8..a695df8 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/security/AwsCognitoTokenFilter.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/security/AwsCognitoTokenFilter.kt @@ -23,13 +23,17 @@ class AwsCognitoTokenFilter( signupUrl: String?, attachmentDownloadUrl: String?, allowedPages: List, + refreshTokenUrl: String?, + webhookUrl: String?, ) : AbstractAuthenticationProcessingFilter(defaultFilterProcessesUrl) { - companion object{ + companion object { private val log = LoggerFactory.getLogger(AwsCognitoTokenFilter::class.java) } private val loginRequestMatcher: RequestMatcher = AntPathRequestMatcher(loginUrl) private val signupRequestMatcher: RequestMatcher = AntPathRequestMatcher(signupUrl) + private val refreshTokenRequestMatcher: RequestMatcher = AntPathRequestMatcher(refreshTokenUrl) + private val webhookRequestMatcher: RequestMatcher = AntPathRequestMatcher(webhookUrl) private val attachmentDownloadRequestMatcher: RequestMatcher = AntPathRequestMatcher(attachmentDownloadUrl) private val allowedPagesRequestMatchers: List = allowedPages.map { AntPathRequestMatcher(it) } @@ -42,6 +46,8 @@ class AwsCognitoTokenFilter( return !loginRequestMatcher.matches(request) && !signupRequestMatcher.matches(request) && !attachmentDownloadRequestMatcher.matches(request) && + !refreshTokenRequestMatcher.matches(request) && + !webhookRequestMatcher.matches(request) && allowedPagesRequestMatchers.all { !it.matches(request) } } diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/PushNotificationService.kt b/src/main/kotlin/io/openfuture/openmessenger/service/PushNotificationService.kt new file mode 100644 index 0000000..851539f --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/PushNotificationService.kt @@ -0,0 +1,63 @@ +package io.openfuture.openmessenger.service + + +import io.openfuture.openmessenger.service.dto.PushNotificationRequest +import io.openfuture.openmessenger.service.firebase.FCMService +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service +import java.util.concurrent.ExecutionException + + +@Service +class PushNotificationService( + private val fcmService: FCMService +) { + private val logger = LoggerFactory.getLogger(PushNotificationService::class.java) + + fun subscribe(tokens: List, topic: String) { + try { + fcmService.subscribeTopic(tokens, topic) + } catch (e: InterruptedException) { + logger.error(e.message) + } catch (e: ExecutionException) { + logger.error(e.message) + } + } + + fun sendPushNotificationWithoutData(request: PushNotificationRequest?) { + try { + fcmService.sendMessageWithoutData(request!!) + } catch (e: InterruptedException) { + logger.error(e.message) + } catch (e: ExecutionException) { + logger.error(e.message) + } + } + + fun sendPushNotificationToToken( + request: PushNotificationRequest + ) { + try { + fcmService.sendMessageToToken(mapOf(), request) + } catch (e: InterruptedException) { + logger.error(e.message) + } catch (e: ExecutionException) { + logger.error(e.message) + } + } + +// private fun toPushData(notificationCreateRequest: NotificationCreateRequest): Map { +// val pushData: MutableMap = HashMap() +// val random = Random() +// pushData["messageId"] = abs(random.nextInt().toDouble()).toString() +// pushData["text"] = LocalDateTime.now().toString() +// pushData["title"] = notificationCreateRequest.getTitle() +// pushData["url"] = notificationCreateRequest.getUrl() +// pushData["click_action"] = "KMP_NOTIFICATION_CLICK" +// pushData["status"] = notificationCreateRequest.getStatus().toString() +// pushData["notificationType"] = notificationCreateRequest.getNotificationType().toString() +// return pushData +// } + + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/TaskService.kt b/src/main/kotlin/io/openfuture/openmessenger/service/TaskService.kt new file mode 100644 index 0000000..9cf2b9f --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/TaskService.kt @@ -0,0 +1,9 @@ +package io.openfuture.openmessenger.service + +import io.openfuture.openmessenger.repository.entity.TaskEntity +import io.openfuture.openmessenger.service.dto.TaskRequest + +interface TaskService { + fun save(taskRequest: TaskRequest): TaskEntity + fun get(email: String): List +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/WalletManagementService.kt b/src/main/kotlin/io/openfuture/openmessenger/service/WalletManagementService.kt new file mode 100644 index 0000000..268146f --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/WalletManagementService.kt @@ -0,0 +1,76 @@ +package io.openfuture.openmessenger.service + + +import io.openfuture.openmessenger.repository.UserFirebaseTokenRepository +import io.openfuture.openmessenger.repository.WalletRepository +import io.openfuture.openmessenger.repository.entity.UserFireBaseToken +import io.openfuture.openmessenger.repository.entity.WalletEntity +import io.openfuture.openmessenger.service.dto.PushNotificationRequest +import io.openfuture.openmessenger.service.dto.SaveWalletRequest +import io.openfuture.openmessenger.service.dto.WebhookPayloadDto +import io.openfuture.openmessenger.service.response.WalletResponse +import org.springframework.stereotype.Service +import java.math.BigDecimal + + +@Service +class WalletManagementService( + private val walletRepository: WalletRepository, + private val pushNotificationService: PushNotificationService, + private val userFirebaseTokenRepository: UserFirebaseTokenRepository +) { + fun saveWallet(request: SaveWalletRequest, username: String): WalletResponse { + + // Save address on db + val wallet = walletRepository.save(WalletEntity( + request.address.lowercase(), + request.blockchainType, + username + )) + + return WalletResponse(wallet.address, wallet.balance, request.blockchainType) + } + + + fun getByUserId(userId: String): List { + return walletRepository.findAllByUserId(userId) + .map { WalletResponse(it.address, it.balance, it.blockchainType) } + } + + fun processWebHook(webhookPayloadDto: WebhookPayloadDto){ + println("State webhook $webhookPayloadDto") + val walletEntity = walletRepository.findFirstByAddress(webhookPayloadDto.walletAddress) + walletEntity.let { entity -> + + val initialBalance : BigDecimal = entity?.balance?.toBigDecimal() ?: BigDecimal.ZERO + entity?.balance = initialBalance.plus(webhookPayloadDto.transaction.amount).toString() + println("Entity $entity") + walletRepository.save(entity!!) + + val fireBaseTokens = userFirebaseTokenRepository.findAllByUserId(entity.userId!!) + println("WebHook response $webhookPayloadDto") + for (token in fireBaseTokens) { + sendNotificationToToken(webhookPayloadDto, token) + } + } + } + + private fun sendNotificationToToken( + webhookPayloadDto: WebhookPayloadDto, + token: UserFireBaseToken + ) { + val blockchainType = when (webhookPayloadDto.blockchain) { + "EthereumBlockchain", "GoerliBlockchain" -> "ETH" + "BinanceBlockchain", "BinanceTestnetBlockchain" -> "BNB" + "TronBlockchain", "TronShastaBlockchain" -> "TRX" + "BitcoinBlockchain" -> "BTC" + else -> "ETH" + } + val message = + "New transaction ${webhookPayloadDto.walletAddress.take(4)}..${webhookPayloadDto.walletAddress.takeLast(2)} - ${webhookPayloadDto.transaction.amount} $blockchainType" + val pushNotificationRequest = + PushNotificationRequest("Transfer", message, "transaction_webhook", token.firebaseToken) + pushNotificationService.sendPushNotificationToToken(pushNotificationRequest) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/DecryptWalletRequest.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/DecryptWalletRequest.kt new file mode 100644 index 0000000..0ba9ced --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/DecryptWalletRequest.kt @@ -0,0 +1,6 @@ +package io.openfuture.openmessenger.service.dto + +data class DecryptWalletRequest( + var encryptedText: String, + var password: String +) diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/KeyResponse.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/KeyResponse.kt new file mode 100644 index 0000000..c6e0bf4 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/KeyResponse.kt @@ -0,0 +1,8 @@ +package io.openfuture.openmessenger.service.dto + + +data class KeyResponse( + val blockchain: String, + var privateKey: String, + var address: String +) diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/PushNotificationRequest.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/PushNotificationRequest.kt new file mode 100644 index 0000000..781915d --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/PushNotificationRequest.kt @@ -0,0 +1,8 @@ +package io.openfuture.openmessenger.service.dto + +class PushNotificationRequest( + var title: String? = null, + val message: String, + val topic: String, + val token: String? = null +) \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/RefreshTokenRequest.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/RefreshTokenRequest.kt index c99620c..e82fdd6 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/service/dto/RefreshTokenRequest.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/RefreshTokenRequest.kt @@ -1,3 +1,3 @@ package io.openfuture.openmessenger.service.dto -data class RefreshTokenRequest(var refreshToken: String) \ No newline at end of file +data class RefreshTokenRequest(var refreshToken: String, var userId: String) \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/SaveWalletRequest.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/SaveWalletRequest.kt new file mode 100644 index 0000000..439fb7d --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/SaveWalletRequest.kt @@ -0,0 +1,9 @@ +package io.openfuture.openmessenger.service.dto + +import io.openfuture.openmessenger.repository.entity.BlockchainType + +data class SaveWalletRequest( + var blockchainType: BlockchainType, + var address: String, + var userId: String +) diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/StateWalletDto.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/StateWalletDto.kt new file mode 100644 index 0000000..8a92ef5 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/StateWalletDto.kt @@ -0,0 +1,11 @@ +package io.openfuture.openmessenger.service.dto + +import java.time.LocalDateTime + +data class StateWalletDto( + val id: String?, + val address: String?, + val webhook: String, + val blockchain: String, + val lastUpdateDate: LocalDateTime? +) diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/TaskRequest.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/TaskRequest.kt new file mode 100644 index 0000000..a97864f --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/TaskRequest.kt @@ -0,0 +1,11 @@ +package io.openfuture.openmessenger.service.dto + +import java.time.LocalDate + +data class TaskRequest( + val assignor: String? , + var assignee: String? , + var taskTitle: String? , + var taskDescription: String? , + var taskDate: LocalDate? +) diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/dto/WebhookPayloadDto.kt b/src/main/kotlin/io/openfuture/openmessenger/service/dto/WebhookPayloadDto.kt new file mode 100644 index 0000000..241955b --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/dto/WebhookPayloadDto.kt @@ -0,0 +1,23 @@ +package io.openfuture.openmessenger.service.dto + +import java.math.BigDecimal +import java.time.LocalDateTime + +data class WebhookPayloadDto( + val blockchain: String, + val walletAddress: String, + val userId: String?,//omit from JSON if null + val metadata: Any?,//omit from JSON if null + val transaction: WebhookTransactionDto +) { + + data class WebhookTransactionDto( + val hash: String, + val from: Set, + val to: String, + val amount: BigDecimal, + val date: LocalDateTime, + val blockHeight: Long, + val blockHash: String + ) +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/firebase/FCMInitializer.kt b/src/main/kotlin/io/openfuture/openmessenger/service/firebase/FCMInitializer.kt new file mode 100644 index 0000000..27604e7 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/firebase/FCMInitializer.kt @@ -0,0 +1,38 @@ +package io.openfuture.openmessenger.service.firebase + +import com.google.auth.oauth2.GoogleCredentials +import com.google.firebase.FirebaseApp +import com.google.firebase.FirebaseOptions +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Configuration +import org.springframework.core.io.ClassPathResource +import org.springframework.stereotype.Service +import java.io.IOException +import javax.annotation.PostConstruct + +@Service +class FCMInitializer { + + @Value("\${app.firebase-configuration-file}") + private val firebaseConfigPath: String? = null + + var logger: Logger = LoggerFactory.getLogger(FCMInitializer::class.java) + + @PostConstruct + fun initialize() { + try { + val options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(ClassPathResource(firebaseConfigPath!!).getInputStream())) + .build() + if (FirebaseApp.getApps().isEmpty()) { + FirebaseApp.initializeApp(options) + logger.info("Firebase application has been initialized") + } + } catch (e: IOException) { + logger.error(e.message) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/firebase/FCMService.kt b/src/main/kotlin/io/openfuture/openmessenger/service/firebase/FCMService.kt new file mode 100644 index 0000000..fad7e92 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/firebase/FCMService.kt @@ -0,0 +1,99 @@ +package io.openfuture.openmessenger.service.firebase + +import com.google.firebase.messaging.* +import io.openfuture.openmessenger.service.dto.PushNotificationRequest +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service +import java.time.Duration +import java.util.concurrent.ExecutionException + +@Service +class FCMService { + private val logger = LoggerFactory.getLogger(FCMService::class.java) + + @Throws(InterruptedException::class, ExecutionException::class) + fun sendMessage(data: Map, request: PushNotificationRequest) { + val message = getPreconfiguredMessageWithData(data, request) + val response = sendAndGetResponse(message) + logger.info(("Sent message with data. Topic: " + request.topic) + ", " + response) + } + + @Throws(InterruptedException::class, ExecutionException::class) + fun sendMessageWithoutData(request: PushNotificationRequest) { + val message = getPreconfiguredMessageWithoutData(request) + val response = sendAndGetResponse(message) + logger.info(("Sent message without data. Topic: " + request.topic) + ", " + response) + } + + @Throws(InterruptedException::class, ExecutionException::class) + fun sendMessageToToken(data: Map, request: PushNotificationRequest) { + val message = getPreconfiguredMessageToToken(data, request) + val response = sendAndGetResponse(message) + logger.info(("Sent message to token. Device token: " + request.token) + ", " + response) + } + + @Throws(InterruptedException::class, ExecutionException::class) + private fun sendAndGetResponse(message: Message): String { + return FirebaseMessaging.getInstance().sendAsync(message).get() + } + + @Throws(ExecutionException::class, InterruptedException::class) + fun subscribeTopic(tokens: List?, topic: String?) { + FirebaseMessaging.getInstance().subscribeToTopicAsync(tokens, topic).get() + } + + @Throws(InterruptedException::class, ExecutionException::class) + fun unsubscribeTopic(tokens: List?, topic: String?): TopicManagementResponse { + return FirebaseMessaging.getInstance().unsubscribeFromTopicAsync(tokens, topic).get() + } + + private fun getAndroidConfig(topic: String): AndroidConfig { + return AndroidConfig.builder() + .setTtl(Duration.ofMinutes(2).toMillis()).setCollapseKey(topic) + .setPriority(AndroidConfig.Priority.HIGH) + .setNotification( + AndroidNotification.builder() + .setSound(NotificationParameter.SOUND.value) + .setColor(NotificationParameter.COLOR.value) + .setTag(topic).build() + ) + .build() + } + + private fun getApnsConfig(topic: String): ApnsConfig { + return ApnsConfig.builder() + .setAps(Aps.builder().setCategory(topic).setThreadId(topic).build()) + .build() + } + + private fun getPreconfiguredMessageToToken(data: Map, request: PushNotificationRequest): Message { + return getPreconfiguredMessageBuilder(request) + .putAllData(data) + .setToken(request.token) + .build() + } + + private fun getPreconfiguredMessageWithoutData(request: PushNotificationRequest): Message { + return getPreconfiguredMessageBuilder(request) + .setTopic(request.topic) + .build() + } + + private fun getPreconfiguredMessageWithData(data: Map, request: PushNotificationRequest): Message { + return getPreconfiguredMessageBuilder(request) + .putAllData(data) + .setTopic(request.topic) + .build() + } + + private fun getPreconfiguredMessageBuilder(request: PushNotificationRequest): Message.Builder { + val androidConfig = getAndroidConfig(request.topic) + val apnsConfig = getApnsConfig(request.topic) + return Message.builder() + .setApnsConfig(apnsConfig) + .setAndroidConfig(androidConfig) + .setNotification( + Notification.builder().setTitle(request.title).setBody(request.message).build() + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/firebase/NotificationParameter.kt b/src/main/kotlin/io/openfuture/openmessenger/service/firebase/NotificationParameter.kt new file mode 100644 index 0000000..257a9da --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/firebase/NotificationParameter.kt @@ -0,0 +1,11 @@ +package io.openfuture.openmessenger.service.firebase + +enum class NotificationParameter( + val value: String +) { + SOUND("default"), + COLOR("#FFFF00"); + companion object { + fun fromInt(value: String) = entries.first { it.value == value } + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/impl/AssistantServiceImpl.kt b/src/main/kotlin/io/openfuture/openmessenger/service/impl/AssistantServiceImpl.kt index 6fe58f1..5265609 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/service/impl/AssistantServiceImpl.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/service/impl/AssistantServiceImpl.kt @@ -90,7 +90,6 @@ class AssistantServiceImpl( val participants: List? = getParticipants(assistantRequest) val objectMapper = jacksonObjectMapper() - objectMapper.registerModule(JavaTimeModule()) val conversation = getConversation(assistantRequest) @@ -105,7 +104,6 @@ class AssistantServiceImpl( ?.replace("```", "") val reminderItemList = objectMapper.readValue>("[$result]") - val defaultObjectMapper = jacksonObjectMapper() val assistantReminderEntity = AssistantReminderEntity( current.email, diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/impl/CognitoUserServiceImpl.kt b/src/main/kotlin/io/openfuture/openmessenger/service/impl/CognitoUserServiceImpl.kt index fb5cbbf..dea622a 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/service/impl/CognitoUserServiceImpl.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/service/impl/CognitoUserServiceImpl.kt @@ -61,7 +61,11 @@ class CognitoUserServiceImpl( setUserPassword(request.email, request.password) createUserResult.user } catch (e: UsernameExistsException) { - throw UsernameExistsException("User name that already exists") + //throw UsernameExistsException("User name that already exists") + log.info("User Exists: {}", e.errorMessage) + val userType = UserType() + userType.username = request.email + return userType } catch (e: com.amazonaws.services.cognitoidp.model.InvalidPasswordException) { throw InvalidPasswordException("Invalid password.", e) } diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/impl/TaskServiceImpl.kt b/src/main/kotlin/io/openfuture/openmessenger/service/impl/TaskServiceImpl.kt new file mode 100644 index 0000000..9440225 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/impl/TaskServiceImpl.kt @@ -0,0 +1,30 @@ +package io.openfuture.openmessenger.service.impl + +import io.openfuture.openmessenger.repository.TaskRepository +import io.openfuture.openmessenger.repository.entity.TaskEntity +import io.openfuture.openmessenger.service.TaskService +import io.openfuture.openmessenger.service.dto.TaskRequest +import lombok.RequiredArgsConstructor +import org.springframework.stereotype.Service + +@Service +@RequiredArgsConstructor +class TaskServiceImpl( + val taskRepository: TaskRepository +) : TaskService { + + override fun save(taskRequest: TaskRequest): TaskEntity { + val taskEntity = TaskEntity( + taskRequest.assignor, + taskRequest.assignee, + taskRequest.taskTitle, + taskRequest.taskDescription, + taskRequest.taskDate + ) + return taskRepository.save(taskEntity) + } + + override fun get(email: String): List { + return taskRepository.findAllByAssigneeOrAssignor(email) + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserAuthServiceImpl.kt b/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserAuthServiceImpl.kt index 84c94c7..226fbe5 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserAuthServiceImpl.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserAuthServiceImpl.kt @@ -43,10 +43,9 @@ class UserAuthServiceImpl( } override fun refreshToken(request: RefreshTokenRequest): AuthenticatedResponse { - val current = current() - val result = cognitoUserService.refreshAccessToken(current.id, request.refreshToken) + val result = cognitoUserService.refreshAccessToken(request.userId, request.refreshToken) return AuthenticatedResponse( - current.email, + request.userId, result?.accessToken, result?.idToken, result?.refreshToken diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserServiceImpl.kt b/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserServiceImpl.kt index 5e110f3..8b7f766 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserServiceImpl.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/service/impl/UserServiceImpl.kt @@ -5,11 +5,13 @@ import io.openfuture.openmessenger.repository.UserJpaRepository import io.openfuture.openmessenger.repository.entity.GroupChat import io.openfuture.openmessenger.repository.entity.User import io.openfuture.openmessenger.service.GroupChatService +import io.openfuture.openmessenger.service.UserAuthService import io.openfuture.openmessenger.service.UserService import io.openfuture.openmessenger.web.request.user.UserDetailsRequest import io.openfuture.openmessenger.web.response.GroupInfo import io.openfuture.openmessenger.web.response.UserDetailsResponse import lombok.RequiredArgsConstructor +import org.springframework.security.core.context.SecurityContextHolder import org.springframework.stereotype.Service @Service @@ -17,7 +19,8 @@ import org.springframework.stereotype.Service class UserServiceImpl( val userJpaRepository: UserJpaRepository, val messageRepository: MessageRepository, - val groupChatService: GroupChatService + val groupChatService: GroupChatService, + val userAuthService: UserAuthService ) : UserService { override fun getAllRecipientsBySender(username: String?): Collection? { @@ -34,10 +37,12 @@ class UserServiceImpl( } override fun getUserDetails(request: UserDetailsRequest): UserDetailsResponse { - val commonGroups = groupChatService.findCommonGroups(request.email, request.username) + val userDetails = userAuthService.current() + println("Current user: $userDetails") + val commonGroups = groupChatService.findCommonGroups(request.email, userDetails.email) val user = userJpaRepository.findByEmail(request.email) val groups = commonGroups!!.stream().map { groupChat: GroupChat? -> GroupInfo(groupChat?.id, groupChat?.name) } .toList() - return UserDetailsResponse(request.email, "", groups) + return UserDetailsResponse(request.email, user?.lastName + " " + user?.lastName, groups) } } \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/response/LoginResponse.kt b/src/main/kotlin/io/openfuture/openmessenger/service/response/LoginResponse.kt index 1373737..a05a97a 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/service/response/LoginResponse.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/service/response/LoginResponse.kt @@ -3,5 +3,6 @@ package io.openfuture.openmessenger.service.response data class LoginResponse( var token: String? = null, var message: String? = null, + val userId: String? = null, var refreshToken: String? = null ) \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/service/response/WalletResponse.kt b/src/main/kotlin/io/openfuture/openmessenger/service/response/WalletResponse.kt new file mode 100644 index 0000000..1a43d01 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/service/response/WalletResponse.kt @@ -0,0 +1,10 @@ +package io.openfuture.openmessenger.service.response + +import io.openfuture.openmessenger.repository.entity.BlockchainType + + +data class WalletResponse( + var address: String? = null, + var balance: String? = null, + var blockchainType: BlockchainType +) \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/web/controller/AuthController.kt b/src/main/kotlin/io/openfuture/openmessenger/web/controller/AuthController.kt index 18a940a..cad5477 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/web/controller/AuthController.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/web/controller/AuthController.kt @@ -41,9 +41,10 @@ class AuthController(val userAuthService: UserAuthService) { fun login(@RequestBody @Validated loginRequest: LoginRequest): LoginResponse { val authenticate = userAuthService.authenticate(loginRequest) return LoginResponse( - authenticate.accessToken, - "User logged in Successfully", - authenticate.refreshToken + token = authenticate.accessToken, + message = "User logged in Successfully", + userId = loginRequest.email, + refreshToken = authenticate.refreshToken ) } @@ -51,9 +52,9 @@ class AuthController(val userAuthService: UserAuthService) { fun refreshToken(@RequestBody @Validated request: RefreshTokenRequest): LoginResponse { val authenticate = userAuthService.refreshToken(request) return LoginResponse( - authenticate.accessToken, - "Token refreshed", - authenticate.refreshToken + token = authenticate.accessToken, + message = "Token refreshed", + refreshToken = authenticate.refreshToken ) } diff --git a/src/main/kotlin/io/openfuture/openmessenger/web/controller/PromptController.kt b/src/main/kotlin/io/openfuture/openmessenger/web/controller/PromptController.kt index 7033af9..5f0f43f 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/web/controller/PromptController.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/web/controller/PromptController.kt @@ -42,17 +42,17 @@ class PromptController( @PostMapping("/notes") fun getAllNotes(@RequestBody request: GetAllNotesRequest): List { - return assistantService.getAllNotes(request) + return assistantService.getAllNotes(request).sortedByDescending { it.generatedAt } } @PostMapping("/todos") fun getAllTodos(@RequestBody request: GetAllTodosRequest): List { - return assistantService.getAllTodos(request) + return assistantService.getAllTodos(request).sortedByDescending { it.generatedAt } } @PostMapping("/reminders") fun getAllReminders(@RequestBody request: GetAllRemindersRequest): List { - return assistantService.getAllReminders(request) + return assistantService.getAllReminders(request).sortedByDescending { it.generatedAt } } } diff --git a/src/main/kotlin/io/openfuture/openmessenger/web/controller/TaskController.kt b/src/main/kotlin/io/openfuture/openmessenger/web/controller/TaskController.kt new file mode 100644 index 0000000..ff05aa6 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/web/controller/TaskController.kt @@ -0,0 +1,32 @@ +package io.openfuture.openmessenger.web.controller + +import io.openfuture.openmessenger.repository.entity.TaskEntity +import io.openfuture.openmessenger.service.TaskService +import io.openfuture.openmessenger.service.UserAuthService +import io.openfuture.openmessenger.service.dto.TaskRequest +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RequestMapping("/api/v1/tasks") +@RestController +class TaskController( + val userAuthService: UserAuthService, + val taskService: TaskService +) { + + @PostMapping + fun create( + @RequestBody request: TaskRequest + ): TaskEntity { + return taskService.save(request) + } + + @GetMapping + fun get(): List { + val currentUser = userAuthService.current() + return taskService.get(currentUser.email!!) + } +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/web/controller/UserFirebaseTokenController.kt b/src/main/kotlin/io/openfuture/openmessenger/web/controller/UserFirebaseTokenController.kt new file mode 100644 index 0000000..a966962 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/web/controller/UserFirebaseTokenController.kt @@ -0,0 +1,40 @@ +package io.openfuture.openmessenger.web.controller + +import io.openfuture.openmessenger.repository.UserFirebaseTokenRepository +import io.openfuture.openmessenger.repository.entity.UserFireBaseToken +import io.openfuture.openmessenger.web.request.FirebaseTokenRequest +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.time.LocalDateTime + +@RestController +@RequestMapping("/api/v1/token") +class UserFirebaseTokenController( + val userFirebaseTokenRepository: UserFirebaseTokenRepository +) { + companion object { + val log: Logger = LoggerFactory.getLogger(UserFirebaseTokenController::class.java) + } + + @PostMapping("/add") + fun addToken( + @RequestBody request: FirebaseTokenRequest, + ): UserFireBaseToken? { + println("Save FCM token request $request") + val userFireBaseToken = UserFireBaseToken(request.userId, request.token) + val fireBaseToken = userFirebaseTokenRepository.findFirstByUserId(request.userId) + return if (fireBaseToken.isPresent) { + fireBaseToken.get().apply { + firebaseToken = request.token + updatedAt = LocalDateTime.now() + }.let { userFirebaseTokenRepository.save(it) } + } else { + userFirebaseTokenRepository.save(userFireBaseToken) + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/web/controller/WalletController.kt b/src/main/kotlin/io/openfuture/openmessenger/web/controller/WalletController.kt new file mode 100644 index 0000000..b5fc705 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/web/controller/WalletController.kt @@ -0,0 +1,91 @@ +package io.openfuture.openmessenger.web.controller + +import io.openfuture.openmessenger.component.state.DefaultStateApi +import io.openfuture.openmessenger.repository.BlockchainContractRepository +import io.openfuture.openmessenger.repository.UserFirebaseTokenRepository +import io.openfuture.openmessenger.repository.entity.BlockchainType +import io.openfuture.openmessenger.service.PushNotificationService +import io.openfuture.openmessenger.service.UserAuthService +import io.openfuture.openmessenger.service.WalletManagementService +import io.openfuture.openmessenger.service.dto.SaveWalletRequest +import io.openfuture.openmessenger.service.dto.PushNotificationRequest +import io.openfuture.openmessenger.service.dto.WebhookPayloadDto +import io.openfuture.openmessenger.service.response.WalletResponse +import org.springframework.web.bind.annotation.* + +@RequestMapping("/api/v1/wallets") +@RestController +class WalletController( + val userAuthService: UserAuthService, + val stateApi: DefaultStateApi, + val walletManagementService: WalletManagementService, + val pushNotificationService: PushNotificationService, + val userFirebaseTokenRepository: UserFirebaseTokenRepository, + val blockchainContractRepository: BlockchainContractRepository +) { + + @PostMapping("/save") + fun saveWallet( + @RequestBody request: SaveWalletRequest + ): WalletResponse { + val currentUser = userAuthService.current() + val wallet = walletManagementService.saveWallet(request, currentUser.email!!) + println("Wallet saved: $wallet") + stateApi.createWallet( + wallet.address!!, + "http://localhost:5001/api/v1/wallets/webhook", + wallet.blockchainType, + "chatx" + ) + + return wallet + } + + @PostMapping("/webhook") + fun processWebHook( + @RequestBody webhookPayloadDto: WebhookPayloadDto + ) { + walletManagementService.processWebHook(webhookPayloadDto) + } + + @PostMapping("/notification") + fun processNotification( + @RequestBody notificationCreate: NotificationCreate + ) { + val tokens = userFirebaseTokenRepository.findAllByUserId(notificationCreate.userId) + for (token in tokens) { + val pushNotificationRequest = PushNotificationRequest( + notificationCreate.title, + notificationCreate.message!!, + "topic", + token.firebaseToken + ) + pushNotificationService.sendPushNotificationToToken(pushNotificationRequest) + } + } + + @GetMapping + fun get(): List { + val currentUser = userAuthService.current() + return walletManagementService.getByUserId(currentUser.email!!) + } + + @GetMapping("/contracts") + fun getContracts(@RequestParam(defaultValue = "true") isTest: Boolean): List { + return blockchainContractRepository.findAllByIsTest(isTest).map { + ContractDto(it.contractName!!, it.contractAddress!!, it.blockchain) + } + } + + data class NotificationCreate( + val userId: String, + val title: String, + val message: String? + ) + + data class ContractDto( + val name: String, + val address: String, + val blockchain: BlockchainType + ) +} diff --git a/src/main/kotlin/io/openfuture/openmessenger/web/request/FirebaseTokenRequest.kt b/src/main/kotlin/io/openfuture/openmessenger/web/request/FirebaseTokenRequest.kt new file mode 100644 index 0000000..4ee2ca3 --- /dev/null +++ b/src/main/kotlin/io/openfuture/openmessenger/web/request/FirebaseTokenRequest.kt @@ -0,0 +1,6 @@ +package io.openfuture.openmessenger.web.request + +data class FirebaseTokenRequest( + val userId: String, + val token: String, +) \ No newline at end of file diff --git a/src/main/kotlin/io/openfuture/openmessenger/web/request/user/UserDetailsRequest.kt b/src/main/kotlin/io/openfuture/openmessenger/web/request/user/UserDetailsRequest.kt index 2bf46ba..1dcd3d1 100644 --- a/src/main/kotlin/io/openfuture/openmessenger/web/request/user/UserDetailsRequest.kt +++ b/src/main/kotlin/io/openfuture/openmessenger/web/request/user/UserDetailsRequest.kt @@ -1,3 +1,3 @@ package io.openfuture.openmessenger.web.request.user -data class UserDetailsRequest(val username: String, val email: String) \ No newline at end of file +data class UserDetailsRequest(val email: String) \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e6318ff..c8f5911 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -56,3 +56,12 @@ server: key-store-type: JKS key-alias: kurento-selfsigned port: 8443 + + +# STATE +state: + base-url: ${OPEN_STATE_URL:http://localhost:8545/api} + +# FIREBASE +app: + firebase-configuration-file: open-chat-5f7ba-firebase-adminsdk-1523p-0a596434ea.json \ No newline at end of file diff --git a/src/main/resources/db/migration/V4__create-tasks-table.sql b/src/main/resources/db/migration/V4__create-tasks-table.sql new file mode 100644 index 0000000..4def696 --- /dev/null +++ b/src/main/resources/db/migration/V4__create-tasks-table.sql @@ -0,0 +1,11 @@ +create table open_tasks +( + id serial primary key, + created_at timestamp, + updated_at timestamp, + assignor varchar(255), + assignee varchar(255), + task_title varchar(255), + task_description text, + task_date date +); \ No newline at end of file diff --git a/src/main/resources/db/migration/V5__create-wallet-table.sql b/src/main/resources/db/migration/V5__create-wallet-table.sql new file mode 100644 index 0000000..c030981 --- /dev/null +++ b/src/main/resources/db/migration/V5__create-wallet-table.sql @@ -0,0 +1,22 @@ +create table open_wallets +( + id serial primary key, + created_at timestamp, + updated_at timestamp, + user_id varchar, + blockchain_type varchar, + address text, + balance varchar +); + +create table wallet_contracts +( + id serial primary key, + created_at timestamp, + updated_at timestamp, + blockchain_type varchar, + address text, + contract_address text, + amount varchar, + from_address text +); \ No newline at end of file diff --git a/src/main/resources/db/migration/V6__create-firebase-token-table.sql b/src/main/resources/db/migration/V6__create-firebase-token-table.sql new file mode 100644 index 0000000..66f12dc --- /dev/null +++ b/src/main/resources/db/migration/V6__create-firebase-token-table.sql @@ -0,0 +1,8 @@ +create table user_firebase_tokens +( + id serial primary key, + created_at timestamp, + updated_at timestamp, + user_id varchar, + firebase_token text +); \ No newline at end of file diff --git a/src/main/resources/db/migration/V7__create-blockchain-contracts-table.sql b/src/main/resources/db/migration/V7__create-blockchain-contracts-table.sql new file mode 100644 index 0000000..b11aadd --- /dev/null +++ b/src/main/resources/db/migration/V7__create-blockchain-contracts-table.sql @@ -0,0 +1,22 @@ +create table blockchain_contracts +( + id serial primary key, + created_at timestamp, + updated_at timestamp, + blockchain varchar, + is_test boolean default false, + contract_name text, + contract_address text, + decimal int +); + +insert into blockchain_contracts +(created_at, updated_at, blockchain, is_test, contract_name, contract_address, decimal) +values (now(), now(), 'ETH', false, 'Tether USDT', '0xdac17f958d2ee523a2206206994597c13d831ec7', 6), + (now(), now(), 'ETH', false, 'USD Coin', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6), + (now(), now(), 'ETH', true, 'Tether USDT', '0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0', 6), + (now(), now(), 'ETH', true, 'USD Coin', '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', 6), + (now(), now(), 'TRX', false, 'Tether USDT', 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', 6), + (now(), now(), 'TRX', true, 'Tether USDT', 'TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs', 6), + (now(), now(), 'BNB', false, 'USDT Token', '0x55d398326f99059ff775485246999027b3197955', 18), + (now(), now(), 'BNB', true, 'USDT Token', '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', 18); \ No newline at end of file diff --git a/src/main/resources/open-chat-5f7ba-firebase-adminsdk-1523p-0a596434ea.json b/src/main/resources/open-chat-5f7ba-firebase-adminsdk-1523p-0a596434ea.json new file mode 100644 index 0000000..af40347 --- /dev/null +++ b/src/main/resources/open-chat-5f7ba-firebase-adminsdk-1523p-0a596434ea.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "open-chat-5f7ba", + "private_key_id": "0a596434ea046a80a9d2613e04de8a7e6fd338ba", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqRuJrqVLYQM/7\nW3V+oEba3w6vbu0/wKiCuTCrhnxiaZ/a9Hk3NK64xWnlX+isDxWrNgz/0RYIiAWZ\niVxy+28vTsDyqWqlsUUGuGa/mBzHJ+Xxxdk8/PAMA6Tv/wn3j+CWarTYtIZ/Nxpy\nnKKqzV8uwF/lbpOPC/pUNkWJFdwLTrQK1Yy/jEPtTFz7TZkFu8kluTL/Jo9UBZkX\nBRqZsnd6WBJMhKQe4JB9ZhvVr07V1DfrVDhZHo/ETys+J0wjLI36Vpsl6w2e3MAk\ngLdVamZtMG9oBuzgpQzPcfT0u6589zDuQ0aZHBSg/Z7X7o7dmnSH7CLBWdHK4kMa\nxAEclwFFAgMBAAECggEAMLhCbZqPhSeaOqmzBw2V6Gb9HS4IfP7DWE/jgJhku4XM\nQspDaovM2DpH7+TOvng8c3XuJz3sZ3l/3KvkQ1P0vpzycRwPUyRTAza802ITDdq5\nHMHGw//9MPrT9QVMlURZ9r/GSeDxQLIEA7oUgvlrHAXYCl3mo33CXNkAcVZLVQJx\n59SbJWoigCYBFUFqQc5ohJ2sg/RAWrVGwJ0YaFs6+jRRksfvpnOqBHL/QlubknFS\nLx3h3IGfY5pN65QvNbQqggCGhyd3LvZWJMqz6GamoCqHOr5kh5b4ZaFOQJ3jmt7c\nSzojGUs1EZuiWWvpHOixdUEklbGCHvRcF4V42Qn6GwKBgQDtJF38gr6bq2kVh6kh\n9lxj96K0LoKXlipEa+CJi9q+6x4tFa185Yvk3gDaT0+Qz1fe38WPRK3fC7BMzWMc\nfC53OSZOrWA04FMcrFYKdBCbcabY/OR6tBgsIHqPB9RX6aIWyB6zRN+4YYymjVin\nWX0a60o5++8wFDFfAShZt4Mj6wKBgQC30U5QQYlubDBwO/f4Bd5Q0UAA0tP6fHzw\njuKAzT7FM8zE6yG+QN6LeFYV4XMtXZFpWMYACFE1rWHUVSV9EaHDQVeALt/9ty3H\nKxMYXOqYVBOzr2hh+BPyQKWN9+7ITw0ck/Ekn7w+Jat/ZKal+x+2tQqRzUIrQq5r\nWPsZNqKTjwKBgCiuo30NRPvZtSZfZpGP/RudQQleLUMqHMguJZATMQytsziSzndt\nvckemNDa6FB0caOnifHhG173V2Bln8okN6h2Ym7+6VFI5pk1q3ERpkO0hKYXBG9U\ndA0l6UCeXDxUtVzpKfMhLqwn+AQenYXgIUk78jjuUoNSA4JD5ZM2m0XPAoGAYmUW\n350FPOeK0jk3ljtF8srf0NEKCXZjxr0lf77eD9+Xh/05VccRmWSz6AiDh9AjS1nq\nuw+4sNv7lxZw987dYVBzzzjIS96nEYr8MLlkFmBDH5cQcAjEXJPASwthdTXjld2X\nYnxi3n15nLq6/fQ72Kh2XO+bsN6D0RCTcL6vLf8CgYAWMaYsuzWgRlJT9EJ/89kw\nGFl30ER9dP2EZicLDSGO09yfXMB/Qxf5cWWP60zdl+HqdqRezaCeSJOzeSXHJULo\nEfe8PiubV9jXZA0uYe+aHp3aTnqgEV5JbjiQBsZd3FBTjTBZ8Hg1gMBtQj8kOabu\nqDwHLz+kL3t5cCP7FWvXMw==\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-1523p@open-chat-5f7ba.iam.gserviceaccount.com", + "client_id": "104183128038717550675", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-1523p%40open-chat-5f7ba.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +}