Skip to content

Commit

Permalink
feat: stargazers 조회 api를 추가한다
Browse files Browse the repository at this point in the history
  • Loading branch information
devxb committed Sep 13, 2024
1 parent 9418ac5 commit 68058a5
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 3 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ test {
}

application {
mainClassName = 'org.gitanimals.render.Application'
mainClassName = 'org.gitanimals.Application'
}

sentry {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.gitanimals.render
package org.gitanimals

import org.rooftop.netx.meta.EnableSaga
import org.springframework.boot.SpringApplication
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.gitanimals.star.controller

import org.gitanimals.star.domain.StargazerService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController

@RestController
class StargazerController(
private val stargazerService: StargazerService,
) {

@GetMapping("/stargazers/{login}/press")
fun isPressStar(@PathVariable("login") login: String): Map<String, Boolean> {
val isPressStar = stargazerService.existsByLogin(login)

return mapOf("isPressStar" to isPressStar)
}
}
12 changes: 12 additions & 0 deletions src/main/kotlin/org/gitanimals/star/domain/Stargazer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.gitanimals.star.domain

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id

@Entity
class Stargazer(
@Id
@Column(name = "login")
val login: String,
)
26 changes: 26 additions & 0 deletions src/main/kotlin/org/gitanimals/star/domain/StargazerService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.gitanimals.star.domain

import jakarta.persistence.EntityManager
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional(readOnly = true)
class StargazerService(
private val stargazersRepository: StargazersRepository,
private val entityManager: EntityManager,
) {

@Cacheable(value = ["exists_by_login_cache"])
fun existsByLogin(login: String): Boolean = stargazersRepository.existsById(login)

@Transactional
fun updateAll(logins: List<String>) {
stargazersRepository.deleteAllInBatch()

logins.map { entityManager.persist(Stargazer(it)) }
entityManager.flush()
entityManager.clear()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.gitanimals.star.domain

import org.springframework.data.jpa.repository.JpaRepository

interface StargazersRepository : JpaRepository<Stargazer, String>
92 changes: 92 additions & 0 deletions src/main/kotlin/org/gitanimals/star/infra/GithubStargazerApi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.gitanimals.star.infra

import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.ClassPathResource
import org.springframework.http.HttpHeaders
import org.springframework.stereotype.Component
import org.springframework.web.client.RestClient
import java.nio.charset.Charset

@Component
class GithubStargazerApi(
@Value("\${github.token}") private val token: String,
) {

private val restClient = RestClient.create("https://api.github.com/graphql")

fun getStargazers(): List<StargazersResponse> {
val stargazers = mutableListOf(getStargazer(""))

while (stargazers.last().pageInfo.hasNextPage) {
val stargazer = getStargazer(stargazers.last().pageInfo.endCursor)
stargazers.add(stargazer)
}

return stargazers
}

private fun getStargazer(endCursor: String): StargazersResponse {
return restClient.post()
.header(HttpHeaders.AUTHORIZATION, "Bearer $token")
.body(
mapOf(
"query" to stargazerQuery.replaceFirst("*{endCursor}", endCursor)
)
).exchange { _, response ->
assertIsSuccess(response)

response.bodyTo(GithubStargazerGraphqlResponse::class.java)!!
.data
.repository
.stargazers
}
}

private fun assertIsSuccess(response: RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse) {
require(response.statusCode.is2xxSuccessful) {
"Bad request cause status : \"${response.statusText}\" message : \"${
response.bodyTo(
String::class.java
)
}\""
}
}

companion object {
private val stargazerQuery: String =
ClassPathResource("github-graphql/stargazer.graphql")
.getContentAsString(Charset.defaultCharset())
}
}

data class GithubStargazerGraphqlResponse(
val data: Data,
) {
data class Data(
val repository: Repository,
) {
data class Repository(
val stargazers: StargazersResponse,
)
}
}

data class StargazersResponse(
val edges: List<StarPushedPeople>,
val pageInfo: PageInfo,
) {

data class StarPushedPeople(
val starredAt: String,
val node: Node,
) {
data class Node(
val login: String,
)
}

data class PageInfo(
val endCursor: String,
val hasNextPage: Boolean,
)
}
36 changes: 36 additions & 0 deletions src/main/kotlin/org/gitanimals/star/infra/StargazerBatchJob.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.gitanimals.star.infra

import org.gitanimals.star.domain.StargazerService
import org.springframework.boot.context.event.ApplicationStartedEvent
import org.springframework.context.event.EventListener
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service

@Service
class StargazerBatchJob(
private val githubStargazerApi: GithubStargazerApi,
private val stargazerService: StargazerService,
) {

@EventListener(ApplicationStartedEvent::class)
fun initStargazer() {
updateStargazer()
}

@Scheduled(cron = EVERY_DAY)
fun updateStargazer() {
val stargazers = githubStargazerApi.getStargazers()
stargazerService.updateAll(
stargazers.flatMap { stargazer ->
stargazer.edges.map { edge ->
edge.node.login
}
}
)
}


companion object {
private const val EVERY_DAY = "0 0 * * * ?"
}
}
18 changes: 18 additions & 0 deletions src/main/resources/github-graphql/stargazer.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
query {
repository(owner: "git-goods", name: "gitanimals") {
stargazers(first: 100, after: "*{endCursor}") {
edges {
starredAt
node {
login
name
url
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.gitanimals.render.app

import io.kotest.assertions.nondeterministic.eventually
import io.kotest.core.spec.style.DescribeSpec
import org.gitanimals.render.Application
import org.gitanimals.Application
import org.gitanimals.render.supports.RedisContainer
import org.gitanimals.render.supports.SagaCapture
import org.springframework.boot.test.context.SpringBootTest
Expand Down

0 comments on commit 68058a5

Please sign in to comment.