Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
mati2251 committed Mar 17, 2024
2 parents 42c9cd3 + a02a4ca commit b366904
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 60 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/backend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ jobs:
run:
working-directory: backend
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
Expand All @@ -33,9 +33,9 @@ jobs:
run:
working-directory: backend
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
Expand All @@ -44,7 +44,7 @@ jobs:
run: gradle ktlintScanning
- name: Upload analysis results to GitHub
if: always()
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: backend/report.sarif
wait-for-processing: true
8 changes: 4 additions & 4 deletions .github/workflows/frontend-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ jobs:
security-events: write
actions: write
steps:
- uses: actions/checkout@v3
- name: Use Node.js 18.x
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: 20.x
cache: 'yarn'
cache-dependency-path: 'frontend/yarn.lock'
- name: Install dependencies
Expand Down
18 changes: 9 additions & 9 deletions .github/workflows/frontend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ jobs:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v3
- name: Use Node.js 18.x
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: 20.x
cache: 'yarn'
cache-dependency-path: 'frontend/yarn.lock'
- name: Install dependencies
Expand All @@ -32,11 +32,11 @@ jobs:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v3
- name: Use Node.js 18.x
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: 20.x
cache: 'yarn'
cache-dependency-path: 'frontend/yarn.lock'
- name: Install dependencies
Expand All @@ -51,7 +51,7 @@ jobs:
--ignore-path .gitignore
continue-on-error: true
- name: Upload analysis results to GitHub
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: frontend/eslint-results.sarif
wait-for-processing: true
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
.idea

# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build
Original file line number Diff line number Diff line change
Expand Up @@ -20,80 +20,95 @@ class PlaylistHandler(
fun getCurrentPlaylists(serverRequest: ServerRequest): Mono<ServerResponse> {
val limit = serverRequest.queryParam("limit").orElse("20").toInt()
val offset = serverRequest.queryParam("offset").orElse("0").toInt()
val body = spotifyPlaylistsService.getCurrentPlaylists(offset, limit).flatMap(PlaylistUtils.toPlaylists)
val body =
spotifyPlaylistsService
.getCurrentPlaylists(offset, limit)
.flatMap(PlaylistUtils.toPlaylists)
return ServerResponse.ok().body(body)
}

fun createPlaylist(serverRequest: ServerRequest): Mono<ServerResponse> {
val requestBody = serverRequest.bodyToMono(SpotifyCreatePlaylistRequestBody::class.java)
val userId = ReactiveSecurityContextHolder.getContext().map { it.authentication.principal.toString() }
val responseBody = Mono.zip(requestBody, userId).flatMap {
spotifyPlaylistsService.createPlaylist(it.t2, it.t1)
}.map {
PlaylistUtils.toPlaylist(it)
}
val userId =
ReactiveSecurityContextHolder.getContext().map {
it.authentication.principal.toString()
}
val responseBody =
Mono.zip(requestBody, userId)
.flatMap { spotifyPlaylistsService.createPlaylist(it.t2, it.t1) }
.map { PlaylistUtils.toPlaylist(it) }
return ServerResponse.ok().body(responseBody)
}

fun getCurrentPlaylistsByName(serverRequest: ServerRequest): Mono<ServerResponse> {
val name = serverRequest.queryParam("name").orElse("")

val body = spotifyPlaylistsService
.getCurrentPlaylists(limit = 999)
.map { it ->
SpotifyPlaylistsResponseBody(
it.total,
it.limit,
it.offset,
it.items.filter { it.name.matches(name.toSearchableRegex()) },
)
}
.flatMap(PlaylistUtils.toPlaylists)
val body =
spotifyPlaylistsService
.getCurrentPlaylists(limit = 999)
.map { it ->
SpotifyPlaylistsResponseBody(
it.total,
it.limit,
it.offset,
it.items.filter { it.name.matches(name.toSearchableRegex()) },
)
}
.flatMap(PlaylistUtils.toPlaylists)
return ServerResponse.ok().body(body)
}

fun getPlaylistDetails(serverRequest: ServerRequest): Mono<ServerResponse> {
val playlistId = serverRequest.pathVariable("playlist-id")
val playlistDetails = spotifyPlaylistsService.getPlaylist(playlistId).flatMap(PlaylistUtils.toPlaylistDetails)
val userDetails = playlistDetails.flatMap {
spotifyUserService.getExternalUserProfile(it.owner.id)
}
return playlistDetails.zipWith(userDetails)
.flatMap {
val picture = if (it.t2.images.isNotEmpty()) {
val playlistDetails =
spotifyPlaylistsService
.getPlaylist(playlistId)
.flatMap(PlaylistUtils.toPlaylistDetails)
val userDetails =
playlistDetails.flatMap { spotifyUserService.getExternalUserProfile(it.owner.id) }
return playlistDetails.zipWith(userDetails).flatMap {
val picture =
if (it.t2.images.isNotEmpty()) {
it.t2.images[0].url
} else {
null
}
it.t1.owner.picture = picture
ServerResponse.ok().body(Mono.just(it.t1))
}
it.t1.owner.picture = picture
ServerResponse.ok().body(Mono.just(it.t1))
}
}

fun updatePlaylistDetails(serverRequest: ServerRequest): Mono<ServerResponse> {
val playlistId = serverRequest.pathVariable("playlist-id")
val requestBody = serverRequest.bodyToMono(SpotifyCreatePlaylistRequestBody::class.java)
val responseBody = Mono.zip(requestBody, Mono.just(playlistId)).flatMap {
spotifyPlaylistsService.updatePlaylistDetails(it.t2, it.t1)
}.map {
PlaylistUtils.toPlaylist(it)
}
val responseBody =
Mono.zip(requestBody, Mono.just(playlistId))
.flatMap { spotifyPlaylistsService.updatePlaylistDetails(it.t2, it.t1) }
.map { PlaylistUtils.toPlaylist(it) }
return ServerResponse.ok().body(responseBody)
}

fun getPlaylistTracks(serverRequest: ServerRequest): Mono<ServerResponse> {
val playlistId = serverRequest.pathVariable("playlist-id")
val playlistTracks =
spotifyPlaylistsService
.getSpotifyPlaylistTracks(playlistId)
.flatMap(PlaylistUtils.toSpotifyPlaylistTracks)
return ServerResponse.ok().body(playlistTracks)
}
fun changePlaylistCover(serverRequest: ServerRequest): Mono<ServerResponse> {
val playlistId = serverRequest.pathVariable("playlist-id")
val requestBody = serverRequest.bodyToMono(String::class.java)

val operation = requestBody.flatMap { spotifyPlaylistsService.changePlaylistCover(playlistId, it) }
val operation =
requestBody.flatMap { spotifyPlaylistsService.changePlaylistCover(playlistId, it) }
return operation.then(ServerResponse.ok().build())
}
}

private fun String.toSearchableRegex(): Regex {
var rename = ".*"
for (ch in this)
rename += "[$ch].*"
for (ch in this) rename += "[$ch].*"

return Regex(rename, RegexOption.IGNORE_CASE)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package pl.akai.fillist.web.models

import kotlinx.serialization.Serializable
import pl.akai.fillist.web.spotifywrapper.models.Track

@Serializable
data class PlaylistTracks(
val href: String,
val limit: Int,
val next: String?,
val offset: Int,
val previous: String?,
val total: Int,
val items: List<Track>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class PlaylistRouter {
GET("/playlists/{playlist-id}/details", playlistHandler::getPlaylistDetails)
// ATTENTION: Update don't work properly (Spotify API bug) (state 2023-03-17)
PUT("/playlists/{playlist-id}", playlistHandler::updatePlaylistDetails)
GET("/playlists/{playlist-id}/tracks", playlistHandler::getPlaylistTracks)
PUT("/playlists/{playlist-id}/cover", playlistHandler::changePlaylistCover)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyCreatePlaylistRequestBody
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylist
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylistTracks
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylistsResponseBody
import reactor.core.publisher.Mono

Expand Down Expand Up @@ -37,6 +38,11 @@ class SpotifyPlaylistsService @Autowired constructor(
.then(getPlaylist(playlistId))
}

fun getSpotifyPlaylistTracks(playlistId: String): Mono<SpotifyPlaylistTracks> {
return spotifyClient.get().uri("/playlists/$playlistId/tracks").retrieve()
.bodyToMono(SpotifyPlaylistTracks::class.java)
}

fun changePlaylistCover(playlistId: String, imageData: String): Mono<Void> {
return spotifyClient.put().uri("/playlists/$playlistId/images")
.bodyValue(imageData)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pl.akai.fillist.web.spotifywrapper.playlists.models

import kotlinx.serialization.Serializable
import pl.akai.fillist.web.spotifywrapper.models.Track

@Serializable
data class SpotifyTrackWrapper(
val track: Track,
)

@Serializable
data class SpotifyPlaylistTracks(
val href: String,
val limit: Int,
val next: String?,
val offset: Int,
val previous: String?,
val total: Int,
val items: List<SpotifyTrackWrapper>,
)
17 changes: 17 additions & 0 deletions backend/src/main/kotlin/pl/akai/fillist/web/utils/PlaylistUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package pl.akai.fillist.web.utils

import pl.akai.fillist.web.models.Playlist
import pl.akai.fillist.web.models.PlaylistDetails
import pl.akai.fillist.web.models.PlaylistTracks
import pl.akai.fillist.web.models.PlaylistsResponseBody
import pl.akai.fillist.web.spotifywrapper.models.OwnerDetails
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylist
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylistTracks
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylistsResponseBody
import reactor.core.publisher.Mono

Expand Down Expand Up @@ -69,4 +71,19 @@ object PlaylistUtils {
}
return name
}

val toSpotifyPlaylistTracks: (SpotifyPlaylistTracks) -> Mono<PlaylistTracks> = { playlistTracks ->
Mono.just(playlistTracks)
.map {
PlaylistTracks(
href = playlistTracks.href,
limit = playlistTracks.limit,
next = playlistTracks.next,
offset = playlistTracks.offset,
previous = playlistTracks.previous,
total = playlistTracks.total,
items = playlistTracks.items.map { it.track },
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@ import pl.akai.fillist.configurations.SpotifyClientConfig
import pl.akai.fillist.configurations.WebTestClientConfig
import pl.akai.fillist.web.models.Playlist
import pl.akai.fillist.web.models.PlaylistDetails
import pl.akai.fillist.web.models.PlaylistTracks
import pl.akai.fillist.web.models.PlaylistsResponseBody
import pl.akai.fillist.web.spotifywrapper.models.ExternalUrls
import pl.akai.fillist.web.spotifywrapper.models.Image
import pl.akai.fillist.web.spotifywrapper.models.Owner
import pl.akai.fillist.web.spotifywrapper.models.*
import pl.akai.fillist.web.spotifywrapper.playlists.SpotifyPlaylistsService
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyCreatePlaylistRequestBody
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylist
import pl.akai.fillist.web.spotifywrapper.playlists.models.SpotifyPlaylistsResponseBody
import pl.akai.fillist.web.spotifywrapper.playlists.models.*
import reactor.core.publisher.Mono

@SpringBootTest()
Expand Down Expand Up @@ -199,6 +196,49 @@ class PlaylistsRouterTests {
}
}

@Test
fun getPlaylistTracks() {
`when`(playlistsService.getSpotifyPlaylistTracks(anyOrNull())).thenReturn(
Mono.just(
SpotifyPlaylistTracks(
href = "href",
limit = 1,
offset = 0,
total = 1,
next = "",
previous = "",
items = listOf(
SpotifyTrackWrapper(
track = Track(
id = "1WiIsyGhDQ0ZAD4vnEjOm3",
name = "name",
uri = "uri",
album = Album(
id = "id",
name = "name",
artists = listOf(),
href = "",
uri = "",
),
artists = listOf(),
),
),
),
),
),
)
webTestClient.get().uri("/playlists/1WiIsyGhDQ0ZAD4vnEjOm3/tracks").exchange()
.expectStatus().isOk.expectBody(PlaylistTracks::class.java).value {
assertNotNull(it.items)
assertEquals(it.items.size, 1)
assertEquals(it.items[0].id, "1WiIsyGhDQ0ZAD4vnEjOm3")
assertEquals(it.items[0].name, "name")
assertEquals(it.items[0].uri, "uri")
assertEquals(it.items[0].album.name, "name")
assertEquals(it.items[0].album.id, "id")
}
}

@Test
fun changePlaylistCover() {
val playlistId = "1B9WyPlzPbkyGMWcGlrgP7"
Expand Down
Loading

0 comments on commit b366904

Please sign in to comment.