diff --git a/compose.yml b/compose.yml
index 8845852..5f30956 100644
--- a/compose.yml
+++ b/compose.yml
@@ -6,7 +6,7 @@ services:
networks:
- mp3_composer
ports:
- - 9000:9000
+ - 9001:9001
postgres:
image: postgres:alpine
container_name: composer_postgres
@@ -41,4 +41,4 @@ services:
networks:
mp3_composer:
- driver: bridge
+ external: true
diff --git a/pom.xml b/pom.xml
index b5836eb..c58dd27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,15 @@
3.2.4
4.0.0
3.2.3
+ 2.8.5
+ 2024.08.29
+
+
+ jitpack.io
+ https://jitpack.io
+
+
@@ -98,6 +106,16 @@
tika-parsers-standard-package
${apache-tika.version}
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ ${springdoc-openapi.version}
+
+
+ com.github.kokorin.jaffree
+ jaffree
+ ${jaffree.version}
+
org.postgresql
diff --git a/src/main/java/com/bivashy/backend/composer/config/SecurityConfig.java b/src/main/java/com/bivashy/backend/composer/config/SecurityConfig.java
index 208b713..88c51d5 100644
--- a/src/main/java/com/bivashy/backend/composer/config/SecurityConfig.java
+++ b/src/main/java/com/bivashy/backend/composer/config/SecurityConfig.java
@@ -25,19 +25,24 @@ public class SecurityConfig {
http.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults())
- // TODO: Temporary to test API, remove after testing
.csrf(c -> c.disable());
return http.build();
}
@Bean
public CustomUserDetailsService customUserDetailsService(UserRepository repository) {
- CustomUserDetails defaultUser = new CustomUserDetails(1, "user", passwordEncoder().encode("password"));
- Optional user = repository.findById(defaultUser.getId());
+ CustomUserDetails defaultUser1 = create(repository, 1, "user", passwordEncoder().encode("password"));
+ CustomUserDetails defaultUser2 = create(repository, 2, "user1", passwordEncoder().encode("password"));
+ return new CustomUserDetailsService(defaultUser1, defaultUser2);
+ }
+
+ private CustomUserDetails create(UserRepository repository, long id, String username, String password) {
+ CustomUserDetails userDetails = new CustomUserDetails(id, username, password);
+ Optional user = repository.findById(userDetails.getId());
if (user.isEmpty()) {
- repository.save(new User(defaultUser.getUsername()));
+ repository.save(new User(userDetails.getUsername()));
}
- return new CustomUserDetailsService(defaultUser);
+ return userDetails;
}
@Bean
diff --git a/src/main/java/com/bivashy/backend/composer/controller/TrackController.java b/src/main/java/com/bivashy/backend/composer/controller/TrackController.java
new file mode 100644
index 0000000..be7fc7b
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/controller/TrackController.java
@@ -0,0 +1,35 @@
+package com.bivashy.backend.composer.controller;
+
+import java.io.IOException;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bivashy.backend.composer.dto.track.AddLocalTrackRequest;
+import com.bivashy.backend.composer.dto.track.TrackResponse;
+import com.bivashy.backend.composer.model.User;
+import com.bivashy.backend.composer.service.TrackService;
+
+@RestController
+public class TrackController {
+ private final TrackService trackService;
+
+ public TrackController(TrackService trackService) {
+ this.trackService = trackService;
+ }
+
+ @PostMapping(path = "/playlist/{playlistId}/track", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public ResponseEntity addLocalTrack(
+ @AuthenticationPrincipal User user,
+ @PathVariable Long playlistId,
+ @ModelAttribute AddLocalTrackRequest request) throws IOException {
+ TrackResponse response = trackService.addLocalTrack(user, playlistId, request);
+ return ResponseEntity.ok(response);
+ }
+}
diff --git a/src/main/java/com/bivashy/backend/composer/dto/track/AddLocalTrackRequest.java b/src/main/java/com/bivashy/backend/composer/dto/track/AddLocalTrackRequest.java
new file mode 100644
index 0000000..e937057
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/dto/track/AddLocalTrackRequest.java
@@ -0,0 +1,9 @@
+package com.bivashy.backend.composer.dto.track;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import jakarta.validation.constraints.NotNull;
+
+public record AddLocalTrackRequest(
+ @NotNull MultipartFile source) {
+}
diff --git a/src/main/java/com/bivashy/backend/composer/dto/track/TrackResponse.java b/src/main/java/com/bivashy/backend/composer/dto/track/TrackResponse.java
new file mode 100644
index 0000000..49ed489
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/dto/track/TrackResponse.java
@@ -0,0 +1,10 @@
+package com.bivashy.backend.composer.dto.track;
+
+public record TrackResponse(
+ Long trackId,
+ String title,
+ String artist,
+ String audioPath,
+ Integer durationSeconds,
+ String fileName) {
+}
diff --git a/src/main/java/com/bivashy/backend/composer/model/TrackMetadata.java b/src/main/java/com/bivashy/backend/composer/model/TrackMetadata.java
index 7feb6be..0d249e9 100644
--- a/src/main/java/com/bivashy/backend/composer/model/TrackMetadata.java
+++ b/src/main/java/com/bivashy/backend/composer/model/TrackMetadata.java
@@ -28,6 +28,9 @@ public class TrackMetadata {
@Column(nullable = false, length = 500)
private String title;
+ @Column(length = 500)
+ private String fileName;
+
@Column(name = "audio_path", nullable = false, length = 500)
private String audioPath;
@@ -46,10 +49,12 @@ public class TrackMetadata {
TrackMetadata() {
}
- public TrackMetadata(Track track, String title, String audioPath, String artist, String thumbnailPath,
+ public TrackMetadata(Track track, String title, String fileName, String audioPath, String artist,
+ String thumbnailPath,
Integer durationSeconds) {
this.track = track;
this.title = title;
+ this.fileName = fileName;
this.audioPath = audioPath;
this.artist = artist;
this.thumbnailPath = thumbnailPath;
@@ -68,6 +73,10 @@ public class TrackMetadata {
return title;
}
+ public String getFileName() {
+ return fileName;
+ }
+
public String getAudioPath() {
return audioPath;
}
diff --git a/src/main/java/com/bivashy/backend/composer/model/TrackPlaylist.java b/src/main/java/com/bivashy/backend/composer/model/TrackPlaylist.java
new file mode 100644
index 0000000..5f1fb9c
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/model/TrackPlaylist.java
@@ -0,0 +1,67 @@
+package com.bivashy.backend.composer.model;
+
+import com.bivashy.backend.composer.model.key.PlaylistTrackId;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.Id;
+import jakarta.persistence.IdClass;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
+@Entity
+@Table(name = "playlist_track")
+@IdClass(PlaylistTrackId.class)
+public class TrackPlaylist {
+
+ @Id
+ @Column(name = "playlist_id", nullable = false)
+ private Long playlistId;
+
+ @Id
+ @Column(name = "track_id", nullable = false)
+ private Long trackId;
+
+ @Column(name = "order_index", nullable = false)
+ private Long order;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "playlist_id", insertable = false, updatable = false)
+ private Playlist playlist;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "track_id", insertable = false, updatable = false)
+ private Track track;
+
+ TrackPlaylist() {
+ }
+
+ public TrackPlaylist(Long playlistId, Long trackId, Long order) {
+ this.playlistId = playlistId;
+ this.trackId = trackId;
+ this.order = order;
+ }
+
+ public Long getPlaylistId() {
+ return playlistId;
+ }
+
+ public Long getTrackId() {
+ return trackId;
+ }
+
+ public Long getOrder() {
+ return order;
+ }
+
+ public Playlist getPlaylist() {
+ return playlist;
+ }
+
+ public Track getTrack() {
+ return track;
+ }
+
+}
diff --git a/src/main/java/com/bivashy/backend/composer/model/key/PlaylistTrackId.java b/src/main/java/com/bivashy/backend/composer/model/key/PlaylistTrackId.java
new file mode 100644
index 0000000..5c1fd71
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/model/key/PlaylistTrackId.java
@@ -0,0 +1,63 @@
+package com.bivashy.backend.composer.model.key;
+
+import java.io.Serializable;
+
+public class PlaylistTrackId implements Serializable {
+ private Long playlistId;
+ private Long trackId;
+
+ PlaylistTrackId() {
+ }
+
+ public PlaylistTrackId(Long playlistId, Long trackId) {
+ this.playlistId = playlistId;
+ this.trackId = trackId;
+ }
+
+ public Long getPlaylistId() {
+ return playlistId;
+ }
+
+ public void setPlaylistId(Long playlistId) {
+ this.playlistId = playlistId;
+ }
+
+ public Long getTrackId() {
+ return trackId;
+ }
+
+ public void setTrackId(Long trackId) {
+ this.trackId = trackId;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((playlistId == null) ? 0 : playlistId.hashCode());
+ result = prime * result + ((trackId == null) ? 0 : trackId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ PlaylistTrackId other = (PlaylistTrackId) obj;
+ if (playlistId == null) {
+ if (other.playlistId != null)
+ return false;
+ } else if (!playlistId.equals(other.playlistId))
+ return false;
+ if (trackId == null) {
+ if (other.trackId != null)
+ return false;
+ } else if (!trackId.equals(other.trackId))
+ return false;
+ return true;
+ }
+}
diff --git a/src/main/java/com/bivashy/backend/composer/repository/SourceTypeRepository.java b/src/main/java/com/bivashy/backend/composer/repository/SourceTypeRepository.java
new file mode 100644
index 0000000..d73d4de
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/repository/SourceTypeRepository.java
@@ -0,0 +1,11 @@
+package com.bivashy.backend.composer.repository;
+
+import java.util.Optional;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.bivashy.backend.composer.model.SourceType;
+
+public interface SourceTypeRepository extends JpaRepository {
+ Optional findByName(String name);
+}
diff --git a/src/main/java/com/bivashy/backend/composer/repository/TrackMetadataRepository.java b/src/main/java/com/bivashy/backend/composer/repository/TrackMetadataRepository.java
new file mode 100644
index 0000000..fe8b689
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/repository/TrackMetadataRepository.java
@@ -0,0 +1,10 @@
+package com.bivashy.backend.composer.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import com.bivashy.backend.composer.model.TrackMetadata;
+
+@Repository
+public interface TrackMetadataRepository extends JpaRepository {
+}
diff --git a/src/main/java/com/bivashy/backend/composer/repository/TrackPlaylistRepository.java b/src/main/java/com/bivashy/backend/composer/repository/TrackPlaylistRepository.java
new file mode 100644
index 0000000..ac385bd
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/repository/TrackPlaylistRepository.java
@@ -0,0 +1,9 @@
+package com.bivashy.backend.composer.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.bivashy.backend.composer.model.TrackPlaylist;
+import com.bivashy.backend.composer.model.key.PlaylistTrackId;
+
+public interface TrackPlaylistRepository extends JpaRepository {
+}
diff --git a/src/main/java/com/bivashy/backend/composer/repository/TrackRepository.java b/src/main/java/com/bivashy/backend/composer/repository/TrackRepository.java
new file mode 100644
index 0000000..52c239c
--- /dev/null
+++ b/src/main/java/com/bivashy/backend/composer/repository/TrackRepository.java
@@ -0,0 +1,10 @@
+package com.bivashy.backend.composer.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import com.bivashy.backend.composer.model.Track;
+
+@Repository
+public interface TrackRepository extends JpaRepository