Skip to content

Commit

Permalink
STUD-380 | Added GetSongSmartLinks API
Browse files Browse the repository at this point in the history
  • Loading branch information
wlara committed Jan 17, 2025
1 parent 1f3f779 commit 071d4f8
Show file tree
Hide file tree
Showing 12 changed files with 229 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,6 @@ interface ConfigRepository {
const val CONFIG_KEY_CLIENT_CONFIG_STUDIO = "clientConfig.studio"
const val CONFIG_KEY_CLIENT_CONFIG_MARKETPLACE = "clientConfig.marketplace"
const val CONFIG_KEY_CLIENT_CONFIG_MOBILE = "clientConfig.mobile"
const val CONFIG_KEY_SONG_SMART_LINKS_CACHE_TTL = "songSmartLinks.cacheTimeToLive"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.newm.server.database.migration

import org.flywaydb.core.api.migration.BaseJavaMigration
import org.flywaydb.core.api.migration.Context
import org.jetbrains.exposed.sql.transactions.transaction

@Suppress("unused")
class V72__CreateSongSmartLinks : BaseJavaMigration() {
override fun migrate(context: Context?) {
transaction {
execInBatch(
listOf(
"""
CREATE TABLE IF NOT EXISTS song_smart_links (
id uuid PRIMARY KEY,
created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
song_id uuid NOT NULL,
store_name TEXT NOT NULL,
url TEXT NOT NULL,
CONSTRAINT fk_song_smart_links_song_id__id FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE NO ACTION
)
""".trimIndent(),
"CREATE INDEX IF NOT EXISTS song_smart_links_song_id_index ON song_smart_links(song_id)",
"INSERT INTO config VALUES ('songSmartLinks.cacheTimeToLive','172800') ON CONFLICT(id) DO NOTHING",
),
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,45 @@
package io.newm.server.features.distribution

import io.newm.server.features.collaboration.model.Collaboration
import io.newm.server.features.distribution.model.*
import io.newm.server.features.distribution.model.AddAlbumResponse
import io.newm.server.features.distribution.model.AddArtistRequest
import io.newm.server.features.distribution.model.AddArtistResponse
import io.newm.server.features.distribution.model.AddParticipantResponse
import io.newm.server.features.distribution.model.AddTrackResponse
import io.newm.server.features.distribution.model.AddUserLabelResponse
import io.newm.server.features.distribution.model.AddUserResponse
import io.newm.server.features.distribution.model.AddUserSubscriptionResponse
import io.newm.server.features.distribution.model.DeleteUserLabelResponse
import io.newm.server.features.distribution.model.DistributeReleaseResponse
import io.newm.server.features.distribution.model.DistributionOutletReleaseStatusResponse
import io.newm.server.features.distribution.model.EvearaSimpleResponse
import io.newm.server.features.distribution.model.GetAlbumResponse
import io.newm.server.features.distribution.model.GetArtistResponse
import io.newm.server.features.distribution.model.GetCountriesResponse
import io.newm.server.features.distribution.model.GetGenresResponse
import io.newm.server.features.distribution.model.GetLanguagesResponse
import io.newm.server.features.distribution.model.GetOutletProfileNamesResponse
import io.newm.server.features.distribution.model.GetOutletsResponse
import io.newm.server.features.distribution.model.GetParticipantsResponse
import io.newm.server.features.distribution.model.GetPayoutBalanceResponse
import io.newm.server.features.distribution.model.GetPayoutHistoryResponse
import io.newm.server.features.distribution.model.GetRolesResponse
import io.newm.server.features.distribution.model.GetTracksResponse
import io.newm.server.features.distribution.model.GetUserLabelResponse
import io.newm.server.features.distribution.model.GetUserResponse
import io.newm.server.features.distribution.model.GetUserSubscriptionResponse
import io.newm.server.features.distribution.model.InitiatePayoutResponse
import io.newm.server.features.distribution.model.SmartLink
import io.newm.server.features.distribution.model.UpdateArtistRequest
import io.newm.server.features.distribution.model.UpdateArtistResponse
import io.newm.server.features.distribution.model.UpdateUserLabelResponse
import io.newm.server.features.distribution.model.ValidateAlbumResponse
import io.newm.server.features.song.model.Release
import io.newm.server.features.song.model.Song
import io.newm.server.features.user.model.User
import io.newm.server.typealiases.UserId
import java.io.File
import java.time.LocalDate
import java.util.*

/**
* Higher level api for working with a music distribution service
Expand Down Expand Up @@ -162,4 +193,9 @@ interface DistributionRepository {
suspend fun createDistributionUserIfNeeded(user: User)

suspend fun createDistributionSubscription(user: User)

suspend fun getSmartLinks(
distributionUserId: String,
distributionReleaseId: Long
): List<SmartLink>
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import io.newm.server.features.distribution.model.GetParticipantsResponse
import io.newm.server.features.distribution.model.GetPayoutBalanceResponse
import io.newm.server.features.distribution.model.GetPayoutHistoryResponse
import io.newm.server.features.distribution.model.GetRolesResponse
import io.newm.server.features.distribution.model.GetSmartLinksResponse
import io.newm.server.features.distribution.model.GetTrackStatusResponse
import io.newm.server.features.distribution.model.GetTracksResponse
import io.newm.server.features.distribution.model.GetUserLabelResponse
Expand All @@ -81,6 +82,7 @@ import io.newm.server.features.distribution.model.OutletStatusCode
import io.newm.server.features.distribution.model.OutletsDetail
import io.newm.server.features.distribution.model.Participant
import io.newm.server.features.distribution.model.Preview
import io.newm.server.features.distribution.model.SmartLink
import io.newm.server.features.distribution.model.Subscription
import io.newm.server.features.distribution.model.Track
import io.newm.server.features.distribution.model.UpdateArtistRequest
Expand Down Expand Up @@ -1761,6 +1763,26 @@ class EvearaDistributionRepositoryImpl(
}
}

override suspend fun getSmartLinks(
distributionUserId: String,
distributionReleaseId: Long
): List<SmartLink> {
val httpResponse = httpClient.get("$evearaApiBaseUrl/smartlinks/$distributionReleaseId") {
contentType(ContentType.Application.Json)
accept(ContentType.Application.Json)
bearerAuth(getEvearaApiToken())
parameter("uuid", distributionUserId)
}
if (!httpResponse.status.isSuccess()) {
throw ServerResponseException(httpResponse, "Error getting smart-links: ${httpResponse.bodyAsText()}")
}
val response: GetSmartLinksResponse = httpResponse.body()
if (!response.success) {
throw ServerResponseException(httpResponse, "Error getting smart-links: success==false")
}
return response.data.orEmpty()
}

private suspend fun createDistributionParticipants(
user: User,
collabs: List<Collaboration>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.newm.server.features.distribution.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class GetSmartLinksResponse(
@SerialName("success")
val success: Boolean,
@SerialName("message")
val message: String? = null,
@SerialName("data")
val data: List<SmartLink>? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.newm.server.features.distribution.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class SmartLink(
@SerialName("store_name")
val storeName: String,
@SerialName("smart_link_url")
val url: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ fun Routing.createSongRoutes() {
)
respond(HttpStatusCode.NoContent)
}
get("smartlinks") {
respond(songRepository.getSmartLinks(songId))
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.newm.server.features.song.database

import io.newm.server.features.song.model.SongSmartLink
import io.newm.server.typealiases.SongId
import org.jetbrains.exposed.dao.UUIDEntity
import org.jetbrains.exposed.dao.UUIDEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import java.time.LocalDateTime
import java.util.UUID

class SongSmartLinkEntity(
id: EntityID<UUID>
) : UUIDEntity(id) {
val createdAt: LocalDateTime by SongSmartLinkTable.createdAt
var songId: EntityID<SongId> by SongSmartLinkTable.songId
var storeName: String by SongSmartLinkTable.storeName
var url: String by SongSmartLinkTable.url

fun toModel(): SongSmartLink =
SongSmartLink(
id = id.value,
storeName = storeName,
url = url
)

companion object : UUIDEntityClass<SongSmartLinkEntity>(SongSmartLinkTable) {
fun findBySongId(
songId: SongId
): List<SongSmartLinkEntity> = find { SongSmartLinkTable.songId eq songId }.toList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.newm.server.features.song.database

import io.newm.server.typealiases.SongId
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.UUIDTable
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.ReferenceOption
import org.jetbrains.exposed.sql.javatime.CurrentDateTime
import org.jetbrains.exposed.sql.javatime.datetime
import java.time.LocalDateTime

object SongSmartLinkTable : UUIDTable(name = "song_smart_links") {
val createdAt: Column<LocalDateTime> = datetime("created_at").defaultExpression(CurrentDateTime)
val songId: Column<EntityID<SongId>> = reference("song_id", SongTable, onDelete = ReferenceOption.NO_ACTION).index()
val storeName: Column<String> = text("store_name")
val url: Column<String> = text("url")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.newm.server.features.song.model

import kotlinx.serialization.Contextual
import kotlinx.serialization.Serializable
import java.util.UUID

@Serializable
data class SongSmartLink(
@Contextual
val id: UUID,
val storeName: String,
val url: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import io.newm.server.features.song.model.AudioUploadReport
import io.newm.server.features.song.model.MintPaymentResponse
import io.newm.server.features.song.model.MintingStatus
import io.newm.server.features.song.model.RefundPaymentResponse
import io.newm.server.features.song.model.Release
import io.newm.server.features.song.model.Song
import io.newm.server.features.song.model.SongFilters
import io.newm.server.features.song.model.Release
import io.newm.server.features.song.model.SongSmartLink
import io.newm.server.typealiases.ReleaseId
import io.newm.server.typealiases.SongId
import io.newm.server.typealiases.UserId
Expand Down Expand Up @@ -116,4 +117,6 @@ interface SongRepository {
songId: SongId,
mintPaymentResponse: MintPaymentResponse
)

suspend fun getSmartLinks(songId: SongId): List<SongSmartLink>
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import io.newm.server.aws.s3.s3UrlStringOf
import io.newm.server.config.repo.ConfigRepository
import io.newm.server.config.repo.ConfigRepository.Companion.CONFIG_KEY_DISTRIBUTION_PRICE_USD
import io.newm.server.config.repo.ConfigRepository.Companion.CONFIG_KEY_MINT_PRICE
import io.newm.server.config.repo.ConfigRepository.Companion.CONFIG_KEY_SONG_SMART_LINKS_CACHE_TTL
import io.newm.server.features.cardano.database.KeyTable
import io.newm.server.features.cardano.model.Key
import io.newm.server.features.cardano.repo.CardanoRepository
Expand All @@ -33,6 +34,7 @@ import io.newm.server.features.song.database.SongEntity
import io.newm.server.features.song.database.SongErrorHistoryTable
import io.newm.server.features.song.database.SongReceiptEntity
import io.newm.server.features.song.database.SongReceiptTable
import io.newm.server.features.song.database.SongSmartLinkEntity
import io.newm.server.features.song.database.SongTable
import io.newm.server.features.song.model.AudioEncodingStatus
import io.newm.server.features.song.model.AudioStreamData
Expand All @@ -44,6 +46,7 @@ import io.newm.server.features.song.model.Release
import io.newm.server.features.song.model.ReleaseType
import io.newm.server.features.song.model.Song
import io.newm.server.features.song.model.SongFilters
import io.newm.server.features.song.model.SongSmartLink
import io.newm.server.features.user.database.UserEntity
import io.newm.server.features.user.database.UserTable
import io.newm.server.features.user.model.UserVerificationStatus
Expand Down Expand Up @@ -856,6 +859,48 @@ internal class SongRepositoryImpl(
}
}

override suspend fun getSmartLinks(songId: SongId): List<SongSmartLink> {
logger.debug { "getSmartLinks: songId = $songId" }
val minCreatedAt = LocalDateTime
.now()
.minusSeconds(configRepository.getLong(CONFIG_KEY_SONG_SMART_LINKS_CACHE_TTL))
val cachedSmartLinks = transaction {
with(SongSmartLinkEntity.findBySongId(songId)) {
takeIf { any { it.createdAt >= minCreatedAt } } ?: run {
forEach { it.delete() }
null
}
}
}
if (!cachedSmartLinks.isNullOrEmpty()) {
logger.debug { "Found ${cachedSmartLinks.size} cached smart-links" }
return cachedSmartLinks.map { it.toModel() }
}
val (distributionUserId, distributionReleaseId) = transaction {
SongEntity[songId].run {
UserEntity[ownerId].distributionUserId to releaseId?.let { ReleaseEntity[it].distributionReleaseId }
}
}
if (distributionUserId == null || distributionReleaseId == null) {
logger.debug { "No distribution: userId = $distributionUserId, releaseId = $distributionReleaseId" }
return emptyList()
}
val networkSmartLinks = distributionRepository
.getSmartLinks(distributionUserId, distributionReleaseId)
.filter { it.url.isNotEmpty() }
logger.debug { "Found ${networkSmartLinks.size} network smart-links" }
return transaction {
val songEntityId = EntityID(songId, SongTable)
networkSmartLinks.map {
SongSmartLinkEntity.new {
this.songId = songEntityId
this.storeName = it.storeName
this.url = it.url
}
}
}.map { it.toModel() }
}

private suspend fun sendMintingStartedNotification(songId: SongId) {
collaborationRepository.invite(songId)
sendMintingNotification("started", songId)
Expand Down

0 comments on commit 071d4f8

Please sign in to comment.