Skip to content

Instantly share code, notes, and snippets.

@lopcode
Created February 18, 2022 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lopcode/60457a994a3b0b0c7daa55e1f6e3227a to your computer and use it in GitHub Desktop.
Save lopcode/60457a994a3b0b0c7daa55e1f6e3227a to your computer and use it in GitHub Desktop.
package sponsor.api.fetcher
import io.ktor.client.HttpClient
import io.ktor.client.call.receive
import io.ktor.client.request.header
import io.ktor.client.request.parameter
import io.ktor.client.request.request
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpMethod
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import sponsor.api.serialization.OffsetDateTimeSerializer
import java.time.OffsetDateTime
class PatreonCampaignMembersFetcher(
private val client: HttpClient,
private val accessToken: String
) : PatreonCampaignMembersFetching {
@Serializable
private data class ResponseBody(
val data: List<Member>,
val included: List<Included>
) {
@Serializable
data class Member(
val attributes: MemberAttributes,
val id: String,
val relationships: MemberRelationships,
val type: String
)
@Serializable
data class MemberAttributes(
@SerialName("full_name") val fullName: String,
@SerialName("patron_status") val patronStatus: String
)
@Serializable
data class MemberRelationships(
@SerialName("currently_entitled_tiers") val currentlyEntitledTiers: TiersRelationship,
val user: UserRelationship
)
@Serializable
data class TiersRelationship(
val data: List<TierData>
)
@Serializable
data class TierData(
val id: String,
val type: String
)
@Serializable
data class UserRelationship(
val data: UserData
)
@Serializable
data class UserData(
val id: String,
val type: String
)
@Serializable
sealed class Included {
abstract val type: String
abstract val id: String
}
@Serializable
@SerialName("user")
data class IncludedUser(
override val type: String,
override val id: String,
val attributes: IncludedUserAttributes
) : Included()
@Serializable
data class IncludedUserAttributes(
@SerialName("full_name") val fullName: String,
@SerialName("hide_pledges") val hidePledges: Boolean,
val vanity: String?
)
@Serializable
@SerialName("tier")
data class IncludedTier(
override val type: String,
override val id: String,
val attributes: IncludedTierAttributes
) : Included()
@Serializable
data class IncludedTierAttributes(
@SerialName("amount_cents") val amountCents: Int,
@Serializable(OffsetDateTimeSerializer::class)
@SerialName("created_at")
val createdAt: OffsetDateTime,
val description: String?,
val title: String?
)
}
override suspend fun fetch(
campaignId: String
): Set<PatreonCampaignMembersFetching.PatronDTO> {
val result = client.request<HttpResponse>("https://www.patreon.com/api/oauth2/v2/campaigns/$campaignId/members") {
method = HttpMethod.Get
parameter("include", "currently_entitled_tiers,user")
parameter("fields[member]", "full_name,patron_status")
parameter("fields[tier]", "title,amount_cents,created_at,description")
parameter("fields[user]", "vanity,full_name,hide_pledges")
header("Authorization", "Bearer $accessToken")
}
// todo: paging
val responseBody = result.receive<ResponseBody>()
return convert(responseBody)
}
private fun convert(
response: ResponseBody
): Set<PatreonCampaignMembersFetching.PatronDTO> {
return response.data.map { memberResponse ->
val userRelationship = (
response.included.first {
it.type == "user" && it.id == memberResponse.relationships.user.data.id
} as ResponseBody.IncludedUser
)
val name = when (userRelationship.attributes.hidePledges) {
true -> null
false -> userRelationship.attributes.vanity ?: memberResponse.attributes.fullName
}
val patronStatus = when (memberResponse.attributes.patronStatus) {
"active_patron" -> PatreonCampaignMembersFetching.Status.ACTIVE
"former_patron" -> PatreonCampaignMembersFetching.Status.FORMER
"declined_payment" -> PatreonCampaignMembersFetching.Status.DECLINED_PAYMENT
else -> PatreonCampaignMembersFetching.Status.UNKNOWN
}
PatreonCampaignMembersFetching.PatronDTO(
name = name,
status = patronStatus,
memberId = memberResponse.id,
userId = userRelationship.id
)
}.toSet()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment