Skip to content

Commit

Permalink
feat: enable delete chat (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitormarcal authored Jan 23, 2024
1 parent cebe5c6 commit 87b96cc
Show file tree
Hide file tree
Showing 19 changed files with 254 additions and 105 deletions.
38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,25 @@ There are docker image packages on github. You can download the latest image wit
For docker, the variables must be in upper case and where is "." it must be "_":
`some.environment.variable` is like `SOME_ENVIRONMENT_VARIABLE` in docker

| Environment variables | obs | example |
|-------------------------------------------|--------------------------------|----------------------------------------------------|
| Database | required | |
| spring.datasource.url | required | jdbc:postgresql://database_host:5432/database_name |
| spring.datasource.username | required | user |
| spring.datasource.password | required | secret |
| -------------------------- | -------------------------- | --------- |
| Email import | feat not required | |
| app.email.enabled | not required | true |
| app.email.host | required to feat | imap.server.com |
| app.email.password | required to feat | secret |
| app.email.port | required to feat | 993 |
| app.email.username | required to feat | someuser |
| app.email.debug | not required | true |
| -------------------------- | | -------------------------- |
| chatvault.host | not required | https://somehost.com ,http://localhost:3000 |
| spring.servlet.multipart.max-file-size | not required | 500MB |
| spring.servlet.multipart.max-request-size | not required | 500MB |
| chatvault.msgparser.dateformat | not required but recommended | dd/MM/yyyy HH:mm |
| Environment variables | obs | example |
|-------------------------------------------|------------------------------|----------------------------------------------------|
| Database | required | |
| spring.datasource.url | required | jdbc:postgresql://database_host:5432/database_name |
| spring.datasource.username | required | user |
| spring.datasource.password | required | secret |
| -------------------------- | -------------------------- | --------- |
| Email import | feat not required | |
| chatvault.email.enabled | not required | true |
| chatvault.email.host | required to feat | imap.server.com |
| chatvault.email.password | required to feat | secret |
| chatvault.email.port | required to feat | 993 |
| chatvault.email.username | required to feat | someuser |
| chatvault.email.debug | not required | true |
| -------------------------- | | -------------------------- |
| chatvault.host | not required | https://somehost.com ,http://localhost:3000 |
| spring.servlet.multipart.max-file-size | not required | 500MB |
| spring.servlet.multipart.max-request-size | not required | 500MB |
| chatvault.msgparser.dateformat | not required but recommended | dd/MM/yyyy HH:mm |
------

* If not defined chatvault.msgparser.dateformat, the application will not be able to resolve ambiguities in certain situations
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ interface BucketService {
fun saveToImportDir(bucketFile: BucketFile)
fun saveTextToBucket(bucketFile: BucketFile, messages: Sequence<String>)
fun loadBucketAsZip(path: String): Resource
fun delete(bucketFile: BucketFile)
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,8 @@ data class Bucket(
fun withPath(path: String): Bucket {
return this.copy(path = this.path + path)
}

fun toBucketFile(): BucketFile {
return BucketFile( fileName = "/", address = this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ interface ChatRepository {
fun setChatNameByChatId(chatId: Long, chatName: String)
fun findAttachmentMessageIdsByChatId(chatId: Long): Sequence<AttachmentInfoOutput>
fun findLastMessageByChatId(chatId: Long): Message?
fun deleteChat(chatId: Long)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import java.nio.file.StandardCopyOption
@Service
@PropertySource("classpath:appservice.properties")
class BucketServiceImpl(
@Value("\${app.bucket.root}") val bucketRootPath: String,
@Value("\${app.bucket.import}") val bucketImportPath: String
@Value("\${chatvault.bucket.root}") val bucketRootPath: String,
@Value("\${chatvault.bucket.import}") val bucketImportPath: String
) : BucketService {

private val logger = LoggerFactory.getLogger(this.javaClass)
Expand Down Expand Up @@ -87,41 +87,59 @@ class BucketServiceImpl(
override fun loadBucketAsZip(path: String): Resource {
try {
return File(bucketRootPath).getDirectoriesWithContentAndZipFiles()
.first { path == it.name }
.let { dir ->
DirectoryZipper.zip(dir).let { resource ->
InputStreamResource(object : FileInputStream(resource.file) {
@Throws(IOException::class)
override fun close() {
super.close()
val isDeleted: Boolean = resource.file.delete()
logger.info(
"export:'{}':" + if (isDeleted) "deleted" else "preserved", resource.file.name
)
}
})
.first { path == it.name }
.let { dir ->
DirectoryZipper.zip(dir).let { resource ->
InputStreamResource(object : FileInputStream(resource.file) {
@Throws(IOException::class)
override fun close() {
super.close()
val isDeleted: Boolean = resource.file.delete()
logger.info(
"export:'{}':" + if (isDeleted) "deleted" else "preserved", resource.file.name
)
}
})
}
}
}
} catch (e: Exception) {
throw BucketServiceException(message = "Fail to zip bucket", throwable = e)
}

}

override fun delete(bucketFile: BucketFile) {
val file = bucketFile.file(bucketRootPath)
logger.info("start to delete bucket at: $file")


if (!file.exists()) {
return
}

Files.walk(file.toPath())
.sorted(reverseOrder())
.forEach {
logger.info("item to delete: {}", it)
Files.delete(it)
}

}

override fun zipPendingImports(chatName: String?): Sequence<Resource> {
try {
return File(bucketImportPath)
.getDirectoriesWithContentAndZipFiles()
.asSequence()
.filter { chatName == null || chatName == it.name }
.map { chatGroupDir ->
if (chatGroupDir.name.endsWith(".zip")) {
UrlResource(chatGroupDir.toURI())
} else {
DirectoryZipper.zipAndDeleteSource(chatGroupDir)
}
.getDirectoriesWithContentAndZipFiles()
.asSequence()
.filter { chatName == null || chatName == it.name }
.map { chatGroupDir ->
if (chatGroupDir.name.endsWith(".zip")) {
UrlResource(chatGroupDir.toURI())
} else {
DirectoryZipper.zipAndDeleteSource(chatGroupDir)
}

}
}
} catch (e: Exception) {
throw BucketServiceException(message = "Fail to zip pending imports", throwable = e)
}
Expand All @@ -130,8 +148,8 @@ class BucketServiceImpl(

override fun deleteZipImported(filename: String) {
val toDelete = BucketFile(
fileName = filename,
address = Bucket(path = "/")
fileName = filename,
address = Bucket(path = "/")
).file(root = bucketImportPath)
toDelete.delete()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
app.bucket.root=/opt/chatvault/archive
app.bucket.import=/opt/chatvault/import
chatvault.bucket.root=/opt/chatvault/archive
chatvault.bucket.import=/opt/chatvault/import
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import org.springframework.integration.support.PropertiesBuilder

@Configuration
@PropertySource("classpath:email.properties")
@ConditionalOnProperty(prefix = "app.email", name = ["enabled"], havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(prefix = "chatvault.email", name = ["enabled"], havingValue = "true", matchIfMissing = true)
class EmailHandlerConfig(
@Value("\${app.email.host}") private val host: String,
@Value("\${app.email.port}") private val port: String,
@Value("\${app.email.username}") private val username: String,
@Value("\${app.email.password}") private val password: String,
@Value("\${app.email.fixed-delay-mlss}") private val fixedDelay: Long,
@Value("\${app.email.debug}") private val emailDebug: Boolean,
@Value("\${app.email.subject-starts-with}") private val subjectStartsWithList: List<String>,
@Value("\${chatvault.email.host}") private val host: String,
@Value("\${chatvault.email.port}") private val port: String,
@Value("\${chatvault.email.username}") private val username: String,
@Value("\${chatvault.email.password}") private val password: String,
@Value("\${chatvault.email.fixed-delay-mlss}") private val fixedDelay: Long,
@Value("\${chatvault.email.debug}") private val emailDebug: Boolean,
@Value("\${chatvault.email.subject-starts-with}") private val subjectStartsWithList: List<String>,
) {

private val logger = LoggerFactory.getLogger(this::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import java.io.InputStream
import java.time.LocalDateTime

@Component
@ConditionalOnProperty(prefix = "app.email", name = ["enabled"], havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(prefix = "chatvault.email", name = ["enabled"], havingValue = "true", matchIfMissing = true)
class EmailMessageHandler(
private val chatFileImporter: ChatFileImporter,
@Value("\${app.email.subject-starts-with}") private val subjectStartsWithList: List<String>,
@Value("\${app.email.debug}") private val emailDebug: Boolean,
@Value("\${chatvault.email.subject-starts-with}") private val subjectStartsWithList: List<String>,
@Value("\${chatvault.email.debug}") private val emailDebug: Boolean,
private val bucketDiskImporter: BucketDiskImporter
) {

Expand Down
16 changes: 8 additions & 8 deletions backend/infra/email/src/main/resources/email.properties
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
app.email.host=<set imap host>
app.email.port=<set imap port>
app.email.username=<set username mail>
app.email.password=<set psw mail>
app.email.fixed-delay-mlss=10000
app.email.subject-starts-with=chat-vault,Conversa do WhatsApp com
app.email.enabled=false
app.email.debug=false
chatvault.email.host=<set imap host>
chatvault.email.port=<set imap port>
chatvault.email.username=<set username mail>
chatvault.email.password=<set psw mail>
chatvault.email.fixed-delay-mlss=10000
chatvault.email.subject-starts-with=chat-vault,Conversa do WhatsApp com
chatvault.email.enabled=false
chatvault.email.debug=false
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import dev.marcal.chatvault.persistence.repository.ChatCrudRepository
import dev.marcal.chatvault.persistence.repository.EventSourceCrudRepository
import dev.marcal.chatvault.persistence.repository.MessageCrudRepository
import dev.marcal.chatvault.repository.ChatRepository
import org.slf4j.LoggerFactory
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Sort
Expand All @@ -25,6 +26,8 @@ class ChatRepositoryImpl(
private val objectMapper: ObjectMapper
) : ChatRepository {

private val logger = LoggerFactory.getLogger(this.javaClass)

@Transactional
override fun saveNewMessages(payload: MessagePayload, eventSource: Boolean) {
if (eventSource) {
Expand Down Expand Up @@ -109,6 +112,14 @@ class ChatRepositoryImpl(
return messageCrudRepository.findTopByChatIdOrderByIdDesc(chatId)?.toMessageDomain()
}

@Transactional
override fun deleteChat(chatId: Long) {
logger.info("start to remove messages from $chatId")
messageCrudRepository.deleteAllByChatId(chatId)
logger.info("start to remove chat from $chatId")
chatCrudRepository.deleteById(chatId)
}

override fun countChatMessages(chatId: Long): Long {
return messageCrudRepository.countByChatId(chatId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ interface MessageCrudRepository : JpaRepository<MessageEntity, Long> {

@Query("SELECT new dev.marcal.chatvault.persistence.dto.AttachmentInfoDTO(m.id, m.attachmentName) FROM MessageEntity m WHERE m.chatId = :chatId AND m.attachmentPath IS NOT NULL")
fun findMessageIdByChatIdAndAttachmentExists(chatId: Long): List<AttachmentInfoDTO>

fun deleteAllByChatId(chatId: Long)
}
Loading

0 comments on commit 87b96cc

Please sign in to comment.