Changeset 0519e8d


Ignore:
Timestamp:
08/05/26 18:33:37 (9 hours ago)
Author:
Filip Gavrilovski <filipgavrilovski28@…>
Branches:
main
Parents:
e111525
Message:

update models and remaining code to align with er version 6

Location:
finkwave/src/main/java/com/ukim/finki/develop/finkwave
Files:
3 added
13 edited
2 moved

Legend:

Unmodified
Added
Removed
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/controller/GlobalExceptionHandler.java

    re111525 r0519e8d  
    1010import org.springframework.http.ResponseEntity;
    1111import org.springframework.security.core.userdetails.UsernameNotFoundException;
     12import org.springframework.web.bind.MissingServletRequestParameterException;
    1213import org.springframework.web.bind.annotation.ExceptionHandler;
    1314import org.springframework.web.bind.annotation.RestControllerAdvice;
     
    9697    }
    9798
     99    @ExceptionHandler(MissingServletRequestParameterException.class)
     100    public ResponseEntity<Map<String, String>> handleMissingParam(MissingServletRequestParameterException ex) {
     101        return ResponseEntity
     102                .status(HttpStatus.BAD_REQUEST)
     103                .body(Map.of("error", "Missing required request parameter '" + ex.getParameterName() + "'."));
     104    }
     105
    98106    @ExceptionHandler(Exception.class)
    99107    public ResponseEntity<Map<String, String>> handleGenericException(Exception ex) {
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/Contribution.java

    re111525 r0519e8d  
    1010@Setter
    1111@Entity
    12 @Table(name = "artist_contributions", schema = "project")
    13 public class ArtistContribution {
     12@Table(name = "contributions", schema = "project")
     13public class Contribution {
    1414    @EmbeddedId
    15     private ArtistContributionId id;
     15    private ContributionId id;
     16
     17    @MapsId("musicalEntityId")
     18    @ManyToOne(fetch = FetchType.LAZY, optional = false)
     19    @OnDelete(action = OnDeleteAction.CASCADE)
     20    @JoinColumn(name = "musical_entity_id", nullable = false)
     21    private MusicalEntity musicalEntity;
    1622
    1723    @MapsId("artistId")
     
    2127    private Artist artist;
    2228
    23     @MapsId("musicalEntityId")
    24     @ManyToOne(fetch = FetchType.LAZY, optional = false)
    25     @OnDelete(action = OnDeleteAction.CASCADE)
    26     @JoinColumn(name = "musical_entity_id", nullable = false)
    27     private MusicalEntity musicalEntity;
    28 
    29     @Column(name = "role", nullable = false, length = Integer.MAX_VALUE)
    30     private String role;
     29    @Column(name = "contribution_order", nullable = false)
     30    private Integer contributionOrder;
    3131
    3232}
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/ContributionId.java

    re111525 r0519e8d  
    1313@Setter
    1414@Embeddable
    15 public class ArtistContributionId implements Serializable {
    16     private static final long serialVersionUID = -3193987026608380950L;
     15public class ContributionId implements Serializable {
     16    private static final long serialVersionUID = -3193987026608380951L;
     17    @Column(name = "musical_entity_id", nullable = false)
     18    private Long musicalEntityId;
     19
    1720    @Column(name = "artist_id", nullable = false)
    1821    private Long artistId;
    19 
    20     @Column(name = "musical_entity_id", nullable = false)
    21     private Long musicalEntityId;
    2222
    2323    @Override
     
    2525        if (this == o) return true;
    2626        if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
    27         ArtistContributionId entity = (ArtistContributionId) o;
    28         return Objects.equals(this.artistId, entity.artistId) &&
    29                 Objects.equals(this.musicalEntityId, entity.musicalEntityId);
     27        ContributionId entity = (ContributionId) o;
     28        return Objects.equals(this.musicalEntityId, entity.musicalEntityId) &&
     29                Objects.equals(this.artistId, entity.artistId);
    3030    }
    3131
    3232    @Override
    3333    public int hashCode() {
    34         return Objects.hash(artistId, musicalEntityId);
     34        return Objects.hash(musicalEntityId, artistId);
    3535    }
    3636
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/MusicalEntity.java

    re111525 r0519e8d  
    3434    private LocalDate releaseDate;
    3535
    36     private String cover;
    37 
    3836    @ManyToOne(fetch = FetchType.LAZY)
    3937    @OnDelete(action = OnDeleteAction.CASCADE)
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/Playlist.java

    re111525 r0519e8d  
    2424    private Long id;
    2525
    26     @Column(name = "cover", length = Integer.MAX_VALUE)
    27     private String cover;
    28 
    2926    @Column(name = "name", nullable = false, length = Integer.MAX_VALUE)
    3027    private String name;
     
    3532    private Listener createdBy;
    3633
    37     public Playlist(String cover, String name, Listener createdBy) {
    38         this.cover = cover;
     34    public Playlist(String name, Listener createdBy) {
    3935        this.name = name;
    4036        this.createdBy = createdBy;
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/User.java

    re111525 r0519e8d  
    3131    private String email;
    3232
    33     @Column(nullable = false, length = Integer.MAX_VALUE)
     33    @Column(name = "password_hash", nullable = false, length = Integer.MAX_VALUE)
    3434    @JsonIgnore
    3535    private String password;
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/AlbumRepository.java

    re111525 r0519e8d  
    1818    @Query("""
    1919        SELECT NEW com.ukim.finki.develop.finkwave.model.dto.MusicalEntityDto(
    20             a.id, me.title, me.genre, 'ALBUM', u.fullName, u.username, me.cover, FALSE )
     20            a.id, me.title, me.genre, 'ALBUM', u.fullName, u.username, CAST(NULL AS string), FALSE )
    2121        FROM Album a
    2222        JOIN a.musicalEntities me
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ArtistContributionRepository.java

    re111525 r0519e8d  
    88import org.springframework.stereotype.Repository;
    99
    10 import com.ukim.finki.develop.finkwave.model.ArtistContribution;
    11 import com.ukim.finki.develop.finkwave.model.ArtistContributionId;
     10import com.ukim.finki.develop.finkwave.model.Contribution;
     11import com.ukim.finki.develop.finkwave.model.ContributionId;
    1212import com.ukim.finki.develop.finkwave.model.dto.ArtistContributionDto;
    1313import com.ukim.finki.develop.finkwave.model.dto.ArtistContributionSummaryDto;
    1414
    1515@Repository
    16 public interface ArtistContributionRepository extends JpaRepository<ArtistContribution, ArtistContributionId> {
     16public interface ArtistContributionRepository extends JpaRepository<Contribution, ContributionId> {
    1717
    1818    @Query("""
    1919        SELECT NEW com.ukim.finki.develop.finkwave.model.dto.ArtistContributionDto(
    20             ac.musicalEntity.id, ac.musicalEntity.title, ac.musicalEntity.genre, ac.role,
     20            ac.musicalEntity.id, ac.musicalEntity.title, ac.musicalEntity.genre, CAST(ac.contributionOrder AS string),
    2121            (CASE WHEN s.id IS NOT NULL THEN 'SONG'
    2222                  WHEN a.id IS NOT NULL THEN 'ALBUM'
    2323                  ELSE 'Unknown' END),
    2424            (CASE WHEN l.id IS NOT NULL THEN true ELSE false END),
    25             ac.musicalEntity.cover,
     25            CAST(NULL AS string),
    2626            s.link)
    27         FROM ArtistContribution ac
     27        FROM Contribution ac
    2828        LEFT JOIN Song s  ON s.musicalEntities.id=ac.musicalEntity.id
    2929        LEFT JOIN Album a ON a.musicalEntities.id=ac.musicalEntity.id
     
    3636    @Query("""
    3737    SELECT NEW com.ukim.finki.develop.finkwave.model.dto.ArtistContributionSummaryDto(
    38     ac.artist.nonAdminUser.user.fullName, ac.role
     38    ac.artist.nonAdminUser.user.fullName, CAST(ac.contributionOrder AS string)
    3939    )
    40     FROM ArtistContribution ac
     40    FROM Contribution ac
    4141    WHERE ac.id.musicalEntityId = :songId
    4242    """)
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/LikeRepository.java

    re111525 r0519e8d  
    2424            u.fullName,
    2525            u.username,
    26             me.cover,
     26            CAST(NULL AS string),
    2727            (CASE WHEN currentUserLike.id IS NOT NULL THEN true ELSE false END))
    2828        FROM Like l
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/PlaylistRepository.java

    re111525 r0519e8d  
    2828    @Query("""
    2929    SELECT NEW com.ukim.finki.develop.finkwave.model.dto.BasicPlaylistDto(
    30     p.id, p.name, p.cover, (SELECT COUNT(*) FROM PlaylistSong ps where ps.playlist.id = p.id)
     30    p.id, p.name, CAST(NULL AS string), (SELECT COUNT(*) FROM PlaylistSong ps where ps.playlist.id = p.id)
    3131    )
    3232    FROM Playlist p
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/SongRepository.java

    re111525 r0519e8d  
    1717    @Query("""
    1818        SELECT NEW com.ukim.finki.develop.finkwave.model.dto.SongWithLinkDto(
    19             s.id, me.title, me.genre, 'SONG', u.fullName, u.username, me.cover,
     19            s.id, me.title, me.genre, 'SONG', u.fullName, u.username, CAST(NULL AS string),
    2020            (CASE WHEN :currentUserId IS NOT NULL AND l.id IS NOT NULL THEN true ELSE false END),
    2121            s.link
     
    3434    @Query("""
    3535        SELECT NEW com.ukim.finki.develop.finkwave.model.dto.SongWithLinkDto(
    36             s.id, me.title, me.genre, 'SONG', u.fullName, u.username, me.cover,
     36            s.id, me.title, me.genre, 'SONG', u.fullName, u.username, CAST(NULL AS string),
    3737            (CASE WHEN :currentUserId IS NOT NULL AND l.id IS NOT NULL THEN true ELSE false END),
    3838            s.link
     
    5757            s.musicalEntities.releasedBy.nonAdminUser.user.fullName,
    5858            s.musicalEntities.releasedBy.nonAdminUser.user.username,
    59             s.musicalEntities.cover,
     59            CAST(NULL AS string),
    6060            (EXISTS (SELECT 1 FROM Like l WHERE l.musicalEntity.id = s.id AND l.listener.id = :currentUserId)),
    6161            s.album.musicalEntities.title,
     
    7171            s.musicalEntities.releasedBy.nonAdminUser.user.fullName,
    7272            s.musicalEntities.releasedBy.nonAdminUser.user.username,
    73             s.musicalEntities.cover,
    7473            s.album.musicalEntities.title,
    7574            s.album.musicalEntities.id
     
    8786        u.fullName,
    8887        u.username,
    89         me.cover,
     88        CAST(NULL AS string),
    9089        (EXISTS (
    9190            SELECT 1 FROM Like l
     
    116115            t.username,
    117116            t.link,
    118             t.cover
     117            NULL
    119118        FROM (
    120119                 SELECT DISTINCT ON (l.song_id)
     
    123122                     u.full_name,
    124123                     u.username,
    125                      me.cover,
    126124                     s.link,
    127125                     l.timestamp
     
    146144            u.fullName,
    147145            u.username,
    148             me.cover,
     146            CAST(NULL AS string),
    149147            (EXISTS (
    150148                SELECT 1 FROM Like l
     
    177175            ELSE NULL
    178176           END),
    179           me.cover,
     177          CAST(NULL AS string),
    180178          me.releaseDate
    181179        )
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/AlbumService.java

    re111525 r0519e8d  
    3636                album.getMusicalEntities().getReleasedBy().getNonAdminUser().getUser().getFullName(),
    3737                album.getMusicalEntities().getReleasedBy().getNonAdminUser().getUser().getUsername(),
    38                 album.getMusicalEntities().getCover(),
     38                null,
    3939                likeRepository.isLikedByUser(currentUserId));
    4040        List<SongWithLinkDto>songsFromAlbum=songRepository.findSongsByAlbum(id,currentUserId);
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/MusicalEntityService.java

    re111525 r0519e8d  
    22
    33import java.io.IOException;
    4 import java.nio.file.Files;
    5 import java.nio.file.Path;
    6 import java.nio.file.Paths;
    74import java.time.LocalDate;
    85import java.util.HashSet;
    96import java.util.List;
    107import java.util.Set;
    11 import java.util.UUID;
    128
    139import org.springframework.stereotype.Service;
    1410import org.springframework.transaction.annotation.Transactional;
    15 import org.springframework.web.multipart.MultipartFile;
    1611
    17 import com.ukim.finki.develop.finkwave.exceptions.InvalidFileException;
    1812import com.ukim.finki.develop.finkwave.model.Album;
    1913import com.ukim.finki.develop.finkwave.model.Artist;
    20 import com.ukim.finki.develop.finkwave.model.ArtistContribution;
    21 import com.ukim.finki.develop.finkwave.model.ArtistContributionId;
     14import com.ukim.finki.develop.finkwave.model.Contribution;
     15import com.ukim.finki.develop.finkwave.model.ContributionId;
    2216import com.ukim.finki.develop.finkwave.model.MusicalEntity;
    2317import com.ukim.finki.develop.finkwave.model.Song;
     
    4337    MusicalEntityRepository musicalEntityRepository;
    4438
    45     private static final long MAX_FILE_SIZE = 2_000_000;
    46     private static final String MAIN_VOCAL_ROLE = "MAIN VOCAL";
    47    
     39    // the publishing artist is always recorded first
     40    private static final int PUBLISHING_ARTIST_ORDER = 1;
     41
    4842    @Transactional
    4943    public void handleSongPublish(PublishSongRequestDto requestDto) throws IOException {
     
    5448                requestDto.getTitle(),
    5549                requestDto.getGenre(),
    56                 requestDto.getCover(),
    5750                artist
    5851        );
     
    6558
    6659        // add publishing artist
    67         saveContribution(artist, musicalEntity, MAIN_VOCAL_ROLE);
     60        saveContribution(artist, musicalEntity, PUBLISHING_ARTIST_ORDER);
    6861
    6962        // add additional contributors
     
    7265
    7366    @Transactional
    74     protected MusicalEntity createMusicalEntity(String title, String genre, MultipartFile cover, Artist releasedBy)
    75             throws IOException {
    76         MusicalEntity.MusicalEntityBuilder builder = MusicalEntity.builder()
     67    protected MusicalEntity createMusicalEntity(String title, String genre, Artist releasedBy) {
     68        MusicalEntity musicalEntity = MusicalEntity.builder()
    7769                .title(title)
    7870                .genre(genre)
    7971                .releaseDate(LocalDate.now())
    80                 .releasedBy(releasedBy);
     72                .releasedBy(releasedBy)
     73                .build();
    8174
    82         if (cover != null && !cover.isEmpty()) {
    83             try {
    84                 String filename = saveCoverPhoto(cover);
    85                 builder.cover("profile-pictures/" + filename);
    86             } catch (Exception ignored) {}
    87         }
    88 
    89         return musicalEntityRepository.save(builder.build());
     75        return musicalEntityRepository.save(musicalEntity);
    9076    }
    9177
    9278    @Transactional
    93     protected void saveContribution(Artist artist, MusicalEntity musicalEntity, String role) {
    94         ArtistContributionId id = new ArtistContributionId();
     79    protected void saveContribution(Artist artist, MusicalEntity musicalEntity, int contributionOrder) {
     80        ContributionId id = new ContributionId();
    9581        id.setArtistId(artist.getId());
    9682        id.setMusicalEntityId(musicalEntity.getId());
    9783
    98         ArtistContribution contribution = new ArtistContribution();
     84        Contribution contribution = new Contribution();
    9985        contribution.setId(id);
    10086        contribution.setArtist(artist);
    10187        contribution.setMusicalEntity(musicalEntity);
    102         contribution.setRole(role);
     88        contribution.setContributionOrder(contributionOrder);
    10389
    10490        artistContributionRepository.save(contribution);
     
    10995        if (contributors == null) return;
    11096
     97        int order = PUBLISHING_ARTIST_ORDER + 1;
    11198        for (ArtistContributionSummaryDto contributorDto : contributors) {
    11299            if (contributorDto.getId() == null) continue;
    113100
    114101            Artist contributor = artistService.getArtistById(contributorDto.getId());
    115             saveContribution(contributor, musicalEntity, contributorDto.getRole());
     102            saveContribution(contributor, musicalEntity, order++);
    116103        }
    117104    }
     
    126113                requestDto.getTitle(),
    127114                requestDto.getGenre(),
    128                 requestDto.getCover(),
    129115                artist
    130116        );
     
    135121
    136122        // add publishing artist
    137         saveContribution(artist, albumMusicalEntity, MAIN_VOCAL_ROLE);
     123        saveContribution(artist, albumMusicalEntity, PUBLISHING_ARTIST_ORDER);
    138124
    139         // track artists already added to avoid duplicates
     125        // track artists already added to avoid duplicates, and the next order slot at album level
    140126        Set<Long> albumContributorIds = new HashSet<>();
    141127        albumContributorIds.add(artist.getId());
     128        int[] nextAlbumOrder = { PUBLISHING_ARTIST_ORDER + 1 };
    142129
    143130        List<AlbumSongsDto> albumSongs = requestDto.getAlbumSongs();
    144131        for (AlbumSongsDto songDto : albumSongs) {
    145             createSongForAlbum(albumMusicalEntity, album, songDto, artist, albumContributorIds);
     132            createSongForAlbum(albumMusicalEntity, album, songDto, artist, albumContributorIds, nextAlbumOrder);
    146133        }
    147134    }
     
    150137    @Transactional
    151138    protected void createSongForAlbum(MusicalEntity albumMe, Album album, AlbumSongsDto songDto,
    152                                      Artist publishingArtist, Set<Long> albumContributorIds) {
     139                                     Artist publishingArtist, Set<Long> albumContributorIds, int[] nextAlbumOrder) {
    153140        MusicalEntity songMusicalEntity = MusicalEntity.builder()
    154141                .title(songDto.getTitle())
    155142                .releaseDate(albumMe.getReleaseDate())
    156143                .releasedBy(albumMe.getReleasedBy())
    157                 .cover(albumMe.getCover())
    158144                .genre(albumMe.getGenre())
    159145                .build();
     
    166152        songRepository.save(song);
    167153
    168         // add publishing artist as MAIN VOCAL to this song
    169         saveContribution(publishingArtist, songMusicalEntity, MAIN_VOCAL_ROLE);
     154        // add publishing artist as first contributor to this song
     155        saveContribution(publishingArtist, songMusicalEntity, PUBLISHING_ARTIST_ORDER);
    170156
    171157        // add song-specific contributors
    172158        List<ArtistContributionSummaryDto> songContributors = songDto.getContributors();
    173159        if (songContributors != null) {
     160            int songOrder = PUBLISHING_ARTIST_ORDER + 1;
    174161            for (ArtistContributionSummaryDto contributorDto : songContributors) {
    175162                if (contributorDto.getId() == null) continue;
    176                
     163
    177164                Artist contributor = artistService.getArtistById(contributorDto.getId());
    178                
     165
    179166                // first add to song
    180                 saveContribution(contributor, songMusicalEntity, contributorDto.getRole());
    181                
     167                saveContribution(contributor, songMusicalEntity, songOrder++);
     168
    182169                // then add to album if not already added
    183170                if (!albumContributorIds.contains(contributor.getId())) {
    184                     saveContribution(contributor, album.getMusicalEntities(), contributorDto.getRole());
     171                    saveContribution(contributor, album.getMusicalEntities(), nextAlbumOrder[0]++);
    185172                    albumContributorIds.add(contributor.getId());
    186173                }
     
    188175        }
    189176    }
    190 
    191 
    192 
    193     private String saveCoverPhoto(MultipartFile coverPhoto) throws IOException {
    194         String contentType = coverPhoto.getContentType();
    195         if (contentType == null || !contentType.startsWith("image/")) {
    196             throw InvalidFileException.invalidType();
    197         }
    198 
    199         if (coverPhoto.getSize() > MAX_FILE_SIZE) {
    200             throw InvalidFileException.tooLarge(MAX_FILE_SIZE);
    201         }
    202 
    203         String filename = UUID.randomUUID() + "-" + coverPhoto.getOriginalFilename();
    204         Path path = Paths.get("uploads/profile-pictures", filename);
    205         Files.copy(coverPhoto.getInputStream(), path);
    206         return filename;
    207     }
    208177}
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/NonAdminUserService.java

    re111525 r0519e8d  
    128128                p.getId(),
    129129                p.getName(),
    130                 p.getCover(),
     130                null,
    131131                p.getCreatedBy().getNonAdminUser().getUser().getFullName(),
    132132                p.getCreatedBy().getNonAdminUser().getUser().getUsername(),
  • finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/PlaylistService.java

    re111525 r0519e8d  
    4646                playlist.getId(),
    4747                playlist.getName(),
    48                 playlist.getCover(),
     48                null,
    4949                playlist.getCreatedBy().getNonAdminUser().getUser().getFullName(),
    5050                playlist.getCreatedBy().getNonAdminUser().getUser().getUsername(),
     
    111111                UserNotFoundException::new
    112112        );
    113         Playlist playlist=playlistRepository.save(new Playlist(null,playlistName,listener));
     113        Playlist playlist=playlistRepository.save(new Playlist(playlistName,listener));
    114114        if (songId!=null){
    115115
Note: See TracChangeset for help on using the changeset viewer.