Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: telegram chat authorization via jira #153

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ data class Chat(
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int?,

@Column(name = "jira_id", nullable = false)
val jiraId: String,
@Column(name = "jira_id")
var jiraId: String?,

@Column(name = "telegram_id", nullable = false)
val telegramId: Long,
Expand Down Expand Up @@ -95,3 +95,19 @@ data class ChatTagId (
@Column(name = "id_chat")
val idChat: Int?
) : Serializable

@Entity
@Table(name = "filters_subscriptions")
data class FilterSubscription(
@EmbeddedId
val id: FilterSubscriptionId
)

@Embeddable
data class FilterSubscriptionId (
@Column(name = "id_filter")
val idFilter: Long,
@ManyToOne
@JoinColumn(name = "id_chat")
val chat: Chat
) : Serializable
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ interface ChatTagRepository : JpaRepository<ChatTag, ChatTagId> {
@Query("delete from ChatTag ct where ct.id.idChat = ?1")
fun deleteByIdChat( chatId: Int)
}

interface FilterSubscriptionRepository : JpaRepository<FilterSubscription, FilterSubscriptionId> {
@Modifying
@Query("delete from FilterSubscription fs where fs.id.idFilter = ?1")
fun deleteByIdFilter(filterId: Long)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ package com.github.mikesafonov.jira.telegram.dto
* @author Mike Safonov
*/
data class SendToAll(val message: String)

data class FilterSubscription(val idFilter: Long, val jiraLogin: String)
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.github.mikesafonov.jira.telegram.endpoint

import com.github.mikesafonov.jira.telegram.dto.FilterSubscription
import com.github.mikesafonov.jira.telegram.dto.SendToAll
import com.github.mikesafonov.jira.telegram.service.ApiService
import org.springframework.web.bind.annotation.DeleteMapping
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.RequestParam
import org.springframework.web.bind.annotation.RestController

/**
Expand All @@ -18,4 +21,14 @@ class ApiEndpoint(private val apiService: ApiService) {
fun sendToAll(@RequestBody sendToAll: SendToAll) {
apiService.sendToAll(sendToAll)
}

@PostMapping("/filters-subscriptions")
fun addFilterSubscription(@RequestBody filterSubscription: FilterSubscription) {
apiService.addFilterSubscription(filterSubscription)
}

@DeleteMapping("/filters-subscriptions")
fun addFilterSubscription(@RequestParam idFilter: Long) {
apiService.deleteAllFilterSubscriptions(idFilter)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.mikesafonov.jira.telegram.service

import com.github.mikesafonov.jira.telegram.dto.FilterSubscription
import com.github.mikesafonov.jira.telegram.dto.SendToAll
import com.github.mikesafonov.jira.telegram.service.telegram.TelegramClient
import org.springframework.stereotype.Service
Expand All @@ -10,12 +11,22 @@ import org.springframework.stereotype.Service
@Service
class ApiService(
private val chatService: ChatService,
private val telegramClient: TelegramClient
private val telegramClient: TelegramClient,
private val filterSubscriptionService: FilterSubscriptionService
) {

fun sendToAll(sendToAll: SendToAll) {
chatService.getAll().forEach {
telegramClient.sendMarkdownMessage(it.telegramId, sendToAll.message)
}
}

fun addFilterSubscription(filterSubscription: FilterSubscription) {
chatService.findByJiraId(filterSubscription.jiraLogin)
?.let { filterSubscriptionService.addSubscription(filterSubscription.idFilter, it) }
}

fun deleteAllFilterSubscriptions(idFilter: Long) {
filterSubscriptionService.deleteAllSubscriptions(idFilter)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@ class ChatService(private val chatRepository: ChatRepository, private val chatTa
val validatedJiraLogin = validateJiraLogin(jiraLogin)
val validatedTelegramId = validateTelegramId(telegramId)

val chat = Chat(null, validatedJiraLogin, validatedTelegramId, State.INIT)
chatRepository.save(chat)
addChatInState(validatedTelegramId, validatedJiraLogin, State.INIT)
}

fun addChatInState(telegramId: Long, jiraId: String?, state: State) {
val chat = Chat(null, jiraId, telegramId, state)
save(chat)
}

fun getAll() : List<Chat> {
return chatRepository.findAll()
}

fun getAllLogins() : List<String> {
return chatRepository.findAll().map { it.jiraId }
return chatRepository.findAll().map { it.jiraId }.filterNotNull()
}

fun findByJiraId(jiraId: String): Chat? {
Expand All @@ -47,6 +51,13 @@ class ChatService(private val chatRepository: ChatRepository, private val chatTa
}
}

fun updateJiraId(telegramId: Long, jiraId: String) {
findByTelegramId(telegramId)?.let {
it.jiraId = jiraId
save(it)
}
}

fun save(chat: Chat): Chat {
return chatRepository.save(chat)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.github.mikesafonov.jira.telegram.service

import com.github.mikesafonov.jira.telegram.dao.Chat
import com.github.mikesafonov.jira.telegram.dao.FilterSubscription
import com.github.mikesafonov.jira.telegram.dao.FilterSubscriptionId
import com.github.mikesafonov.jira.telegram.dao.FilterSubscriptionRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class FilterSubscriptionService(
private val repository: FilterSubscriptionRepository
) {

fun getAll(): List<FilterSubscription> {
return repository.findAll()
}

fun addSubscription(idFilter: Long, chat: Chat) {
repository.save(FilterSubscription(FilterSubscriptionId(idFilter, chat)))
}

@Transactional
fun deleteAllSubscriptions(idFilter: Long) {
repository.deleteByIdFilter(idFilter)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ class TagService(private val repository: TagRepository) {
@Transactional
fun getJiraLoginsByTagKey(key: String): List<String> {
val tag = getTagByKey(key) ?: return emptyList()
return tag.chats.map { it.jiraId }
return tag.chats.mapNotNull { it.jiraId }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.github.mikesafonov.jira.telegram.service.destination

import com.github.mikesafonov.jira.telegram.dto.Event
import com.github.mikesafonov.jira.telegram.service.FilterSubscriptionService
import com.github.mikesafonov.jira.telegram.service.jira.JiraApiService
import org.springframework.stereotype.Service

@Service
class FilterSubscriptionDestinationDetector(
val filterSubscriptionService: FilterSubscriptionService,
val jiraApiService: JiraApiService
) :
DestinationDetectorService {
override fun findDestinations(event: Event): List<String> {
if (!event.isIssueEvent || event.issue == null) return emptyList()

return filterSubscriptionService.getAll()
.mapNotNull {
if (jiraApiService.getIssueByFilter(it.id.chat.telegramId, it.id.idFilter)
.any { issue -> issue.id == event.issue.id }
) {
return@mapNotNull it.id.chat.jiraId
}
return@mapNotNull null
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.mikesafonov.jira.telegram.service.jira

import com.atlassian.jira.rest.client.api.domain.Issue
import com.atlassian.jira.rest.client.api.domain.User
import com.github.mikesafonov.jira.telegram.config.conditional.ConditionalOnJiraOAuth
import org.springframework.stereotype.Service

Expand All @@ -18,16 +19,15 @@ class JiraApiService(private val jiraRestClientFactory: JiraRestClientFactory) {
* @param jiraId jira id (login)
*/
fun getMyIssues(telegramId: Long, jiraId: String): Iterable<Issue> {
val jiraRestClient = jiraRestClientFactory.createRestClient(telegramId)
val jql = JQLBuilder.builder()
.unresolved()
.assignedTo(jiraId)
.orderByDateCreate()
.build()
jiraRestClientFactory.createRestClient(telegramId).use {
val jql = JQLBuilder.builder()
.unresolved()
.assignedTo(jiraId)
.orderByDateCreate()
.build()

val issues = jiraRestClient.searchClient.searchJql(jql).claim().issues
jiraRestClient.close()
return issues
return it.searchClient.searchJql(jql).claim().issues
}
}

/**
Expand All @@ -36,9 +36,28 @@ class JiraApiService(private val jiraRestClientFactory: JiraRestClientFactory) {
* @param issueKey jira issue key
*/
fun getDescription(telegramId: Long, issueKey: String): Issue? {
return jiraRestClientFactory.createRestClient(telegramId)
.issueClient
.getIssue(issueKey)
.claim()
jiraRestClientFactory.createRestClient(telegramId).use {
return it.issueClient
.getIssue(issueKey)
.claim()
}
}

fun getMySelf(telegramId: Long): User? {
jiraRestClientFactory.createMySelfRestClient(telegramId).use {
return it.getMySelf()
.claim()
}
}

fun getIssueByFilter(telegramId: Long, filterId: Long): List<Issue> {
jiraRestClientFactory.createRestClient(telegramId).use { restClient ->
return restClient
.searchClient
.getFilter(filterId)
.claim()
?.let { filter -> return restClient.searchClient.searchJql(filter.jql).claim().issues.toList() }
?: emptyList()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.mikesafonov.jira.telegram.service.jira

import com.atlassian.jira.rest.client.api.JiraRestClient
import com.atlassian.jira.rest.client.internal.async.AsynchronousHttpClientFactory
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory
import com.github.mikesafonov.jira.telegram.config.JiraOAuthProperties
import com.github.mikesafonov.jira.telegram.config.conditional.ConditionalOnJiraOAuth
Expand All @@ -26,4 +27,12 @@ class JiraRestClientFactory(
JiraOAuthAuthenticationHandler(oAuthParameters)
)
}

fun createMySelfRestClient(telegramId: Long): MySelfRestClient {
val oAuthParameters = authService.getOAuthParameters(telegramId)
val serverUri = URI(jiraProperties.baseUrl)
val httpClient = AsynchronousHttpClientFactory().createClient(serverUri,
JiraOAuthAuthenticationHandler(oAuthParameters))
return MySelfRestClient(httpClient, serverUri)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.github.mikesafonov.jira.telegram.service.jira

import com.atlassian.jira.rest.client.api.domain.User
import com.atlassian.jira.rest.client.internal.async.AbstractAsynchronousRestClient
import com.atlassian.jira.rest.client.internal.async.DisposableHttpClient
import com.atlassian.jira.rest.client.internal.json.UserJsonParser
import io.atlassian.util.concurrent.Promise
import java.io.Closeable
import java.io.IOException
import java.net.URI
import javax.ws.rs.core.UriBuilder


class MySelfRestClient(private val httpClient: DisposableHttpClient, serverUri: URI) :
AbstractAsynchronousRestClient(httpClient),
Closeable {

private val baseUri: URI
private val userJsonParser = UserJsonParser()

init {
baseUri = UriBuilder.fromUri(serverUri).path("/rest/api/latest").build()
}

fun getMySelf(): Promise<User> {
val userUri = UriBuilder.fromUri(baseUri).path("myself").build()
return getAndParse(userUri, userJsonParser)
}

override fun close() {
try {
httpClient.destroy()
} catch (e: Exception) {
throw if (e is IOException) e else IOException(e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ data class TelegramCommand(
}

fun isAnonymous() : Boolean{
return chat == null
return chat?.jiraId == null && chat?.state != State.WAIT_APPROVE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.github.mikesafonov.jira.telegram.service.AuthorizationService
import com.github.mikesafonov.jira.telegram.service.ChatService
import mu.KotlinLogging
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.telegram.telegrambots.meta.api.objects.Message
import org.telegram.telegrambots.meta.api.objects.Update

Expand All @@ -22,6 +23,7 @@ class TelegramUpdateManager(
/**
* process [update]
*/
@Transactional
fun onUpdate(update: Update) {
if (update.hasMessage() && update.message.hasText()) {
val telegramCommand = toCommand(update.message)
Expand All @@ -45,7 +47,9 @@ class TelegramUpdateManager(
command: TelegramCommand,
nextState: State
) {
if (command.chat != null && command.chat.state != nextState) {
if (command.chat == null) {
chatService.addChatInState(command.chatId, null, nextState)
} else if (command.chat.state != nextState) {
command.chat.state = nextState
chatService.save(command.chat)
}
Expand Down
Loading