Changeset 0f71490
- Timestamp:
- 01/27/26 12:55:23 (6 months ago)
- Branches:
- main
- Children:
- 4e5cf92
- Parents:
- c6e1892
- Files:
-
- 11 edited
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistContributionDTO.java (modified) (1 diff)
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/NonAdminUserDTO.java (modified) (1 diff)
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ArtistContributionRepository.java (modified) (1 diff)
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/FollowRepository.java (modified) (2 diffs)
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ArtistService.java (modified) (1 diff)
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/AuthService.java (modified) (2 diffs)
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/NonAdminUserService.java (modified) (8 diffs)
-
frontend/src/components/userProfile/AllUsersHelper.tsx (modified) (3 diffs)
-
frontend/src/components/userProfile/ArtistView.tsx (modified) (4 diffs)
-
frontend/src/components/userProfile/UserDetailView.tsx (modified) (5 diffs)
-
frontend/src/types.ts (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistContributionDTO.java
rc6e1892 r0f71490 11 11 private Long musicalEntityId; 12 12 private String title; 13 private String genre; 13 14 private String role; 14 15 private String entityType; -
finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/NonAdminUserDTO.java
rc6e1892 r0f71490 18 18 private Long followers; 19 19 private Long following; 20 private Boolean isFollowedByCurrentUser; 20 21 21 22 -
finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ArtistContributionRepository.java
rc6e1892 r0f71490 13 13 public interface ArtistContributionRepository extends JpaRepository<ArtistContribution, ArtistContributionId> { 14 14 15 @Query("SELECT ac.musicalEntity.id,ac.musicalEntity.title,ac. role, "+16 "CASE WHEN s.id IS NOT NULL THEN 'S ong' "+17 "WHEN a.id IS NOT NULL THEN 'A lbum' "+15 @Query("SELECT ac.musicalEntity.id,ac.musicalEntity.title,ac.musicalEntity.genre,ac.role, "+ 16 "CASE WHEN s.id IS NOT NULL THEN 'SONG' "+ 17 "WHEN a.id IS NOT NULL THEN 'ALBUM' "+ 18 18 "ELSE 'Unknown' END "+ 19 19 "FROM ArtistContribution ac "+ -
finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/FollowRepository.java
rc6e1892 r0f71490 2 2 3 3 import org.springframework.data.jpa.repository.JpaRepository; 4 import org.springframework.data.jpa.repository.Query; 5 import org.springframework.data.repository.query.Param; 4 6 import org.springframework.stereotype.Repository; 5 7 … … 16 18 long countByFollowerId(Long userId); 17 19 20 @Query("SELECT CASE WHEN COUNT (f)>0 THEN true ELSE false END " + 21 "FROM Follow f "+ 22 "WHERE f.followee.id=:selectedUserId AND f.follower.id=:currentUserId") 23 boolean isFollowing(@Param("currentUserId") Long currentUSerId,@Param("selectedUserId")Long selectedUserId); 24 18 25 } -
finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ArtistService.java
rc6e1892 r0f71490 23 23 24 24 return results.stream() 25 .map(row->new ArtistContributionDTO((Long)row[0], (String)row[1], (String)row[2], (String)row[3]))25 .map(row->new ArtistContributionDTO((Long)row[0], (String)row[1], (String)row[2],(String)row[3], (String)row[4])) 26 26 .collect(Collectors.toList()); 27 27 } -
finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/AuthService.java
rc6e1892 r0f71490 1 1 package com.ukim.finki.develop.finkwave.service; 2 2 3 import org.springframework.security.core.Authentication; 4 import org.springframework.security.core.context.SecurityContextHolder; 3 5 import org.springframework.security.crypto.password.PasswordEncoder; 4 6 import org.springframework.stereotype.Service; … … 98 100 } 99 101 102 public Long getCurrentUserID(){ 103 Authentication authentication= SecurityContextHolder.getContext().getAuthentication(); 104 if (authentication == null || !authentication.isAuthenticated()) { 105 throw new RuntimeException("User not authenticated"); 106 } 107 108 String username=authentication.getName(); 109 110 111 return userRepository.findByUsername(username).map(User::getId) 112 .orElseThrow(()->new RuntimeException("User not found")); 113 } 114 115 100 116 private User createNonAdminUser(AuthRequestDto authRequestDto) throws IOException { 101 117 User.UserBuilder userBuilder = User.builder() -
finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/NonAdminUserService.java
rc6e1892 r0f71490 1 1 package com.ukim.finki.develop.finkwave.service; 2 2 3 import com.ukim.finki.develop.finkwave.model.Artist; 4 import com.ukim.finki.develop.finkwave.model.Listener; 5 import com.ukim.finki.develop.finkwave.model.NonAdminUser; 6 import com.ukim.finki.develop.finkwave.model.Playlist; 3 import com.ukim.finki.develop.finkwave.model.*; 7 4 import com.ukim.finki.develop.finkwave.model.dto.*; 8 import com.ukim.finki.develop.finkwave.repository.ArtistRepository; 9 import com.ukim.finki.develop.finkwave.repository.FollowRepository; 10 import com.ukim.finki.develop.finkwave.repository.ListenerRepository; 11 import com.ukim.finki.develop.finkwave.repository.NonAdminUserRepository; 5 import com.ukim.finki.develop.finkwave.repository.*; 12 6 import com.ukim.finki.develop.finkwave.service.mappers.NonAdminUserMapper; 13 7 import lombok.AllArgsConstructor; 8 import org.springframework.security.core.Authentication; 9 import org.springframework.security.core.context.SecurityContextHolder; 14 10 import org.springframework.stereotype.Service; 15 11 import org.springframework.transaction.annotation.Transactional; … … 27 23 private final ListenerService listenerService; 28 24 private final FollowRepository followRepository; 25 private final AuthService authService; 29 26 30 27 @Transactional(readOnly = true) … … 44 41 Long followers=followRepository.countByFolloweeId(id); 45 42 Long following=followRepository.countByFollowerId(id); 43 Long currentUserId= authService.getCurrentUserID(); 44 45 boolean isFollowedByCurrentUser=false; 46 if (currentUserId != null) { 47 isFollowedByCurrentUser = followRepository.isFollowing(currentUserId, id); 48 } 49 NonAdminUserDTO dto; 46 50 47 51 if (artistRepository.existsById(id)) { 48 return getArtistProfile(id,followers,following); 52 dto=getArtistProfile(id, followers, following); 53 dto.setIsFollowedByCurrentUser(isFollowedByCurrentUser); 54 return dto; 49 55 } 50 56 51 57 if (listenerRepository.existsById(id)) { 52 return getListenerProfile(id,followers,following); 58 dto=getListenerProfile(id, followers, following); 59 dto.setIsFollowedByCurrentUser(isFollowedByCurrentUser); 60 return dto; 53 61 } 54 62 … … 59 67 Artist artist = artistRepository.findByIdWithUser(artistId) 60 68 .orElseThrow(() -> new RuntimeException("Artist not found with id: " + artistId)); 61 62 69 70 63 71 ArtistMusicalEntitiesDTO entitiesDTO = new ArtistMusicalEntitiesDTO(); 64 72 entitiesDTO.setContributions(artistService.getArtistContributions(artistId)); 65 73 66 74 return mapper.toArtistDTO(artist, entitiesDTO,followers,following); 67 75 } … … 70 78 Listener listener = listenerRepository.findByIdWithUser(listenerId) 71 79 .orElseThrow(() -> new RuntimeException("Listener not found with id: " + listenerId)); 72 73 80 81 74 82 ListenerLikesDTO likesDTO = listenerService.getLikedEntities(listenerId); 75 83 List<PlaylistDTO>playlists=listenerService.getPlaylistsCreatedByUser(listenerId).stream() … … 80 88 p.getCreatedBy().getNonAdminUser().getUser().getFullName() 81 89 )).toList(); 82 90 83 91 return mapper.toListenerDTO(listener, likesDTO,followers,following,playlists); 84 92 } … … 86 94 87 95 public List<NonAdminUserDTO>searchUsers(String name){ 96 97 List<NonAdminUser>nonAdminUsers=nonAdminUserRepository.searchByName(name); 98 if (nonAdminUsers.isEmpty()){ 99 throw new RuntimeException("No user found"); 100 } 101 88 102 return nonAdminUserRepository.searchByName(name).stream() 89 103 .map(user -> { … … 96 110 } 97 111 112 113 98 114 private String determineType(Long id) { 99 115 if (artistRepository.existsById(id)) { -
frontend/src/components/userProfile/AllUsersHelper.tsx
rc6e1892 r0f71490 1 1 import React, { useEffect, useState } from "react"; 2 2 import { useNavigate } from "react-router-dom"; 3 3 import axiosInstance from "../../api/axiosInstance"; 4 4 interface User { 5 5 id: number; … … 16 16 useEffect(() => { 17 17 const fetchUsers = async () => { 18 const response = await fetch("http://localhost:8080/users/all"); 19 const data = await response.json(); 20 setUsers(data); 18 const response = axiosInstance.get("/users/all"); 19 setUsers((await response).data); 21 20 }; 22 21 fetchUsers(); … … 30 29 e.preventDefault(); 31 30 try { 32 const response = await fetch( 33 `http://localhost:8080/users/search?name=${searchedUser}`, 34 ); 35 if (!response.ok) throw new Error("Search failed"); 36 37 const data = await response.json(); 38 setUsers(data); 31 const response = await axiosInstance.get(`/users/search`, { 32 params: { name: searchedUser }, 33 }); 34 setUsers(response.data); 39 35 } catch (err: any) { 40 setError(err.message); 36 const errorMessage = err.response?.data?.error || "Search failed"; 37 setError(errorMessage); 41 38 } 42 39 }; 43 40 44 41 if (users.length == 0) return <div className="p-6">Loading...</div>; 42 if (error) { 43 return ( 44 <div className="p-6 bg-red-50 border border-red-200 text-red-700 rounded-lg"> 45 <h2 className="font-bold">Error</h2> 46 <p>{error}</p> 47 </div> 48 ); 49 } 45 50 46 51 return ( -
frontend/src/components/userProfile/ArtistView.tsx
rc6e1892 r0f71490 1 1 import { useNavigate } from "react-router-dom"; 2 2 import { Music, Disc3, Mic2 } from "lucide-react"; 3 4 interface ArtistContributionDTO { 5 musicalEntityId: number; 6 title: string; 7 role: string; 8 entityType: string; 9 } 3 import type { ArtistContributionDTO } from "../../types"; 10 4 11 5 interface ArtistViewProps { … … 16 10 const navigate = useNavigate(); 17 11 18 const albums = contributions.filter((c) => c.entityType === "A lbum");19 const songs = contributions.filter((c) => c.entityType === "S ong");12 const albums = contributions.filter((c) => c.entityType === "ALBUM"); 13 const songs = contributions.filter((c) => c.entityType === "SONG"); 20 14 21 15 const getRoleColor = (role: string) => { … … 31 25 return ( 32 26 <div className="mt-8"> 33 {/* Albums Section */}34 27 {albums.length > 0 && ( 35 28 <div className="mb-12"> … … 91 84 </h3> 92 85 <div className="flex items-center gap-2 mt-1"> 93 <Mic2 className="w-4 h-4 text-gray-400" />86 {song.genre} 94 87 </div> 95 88 </div> -
frontend/src/components/userProfile/UserDetailView.tsx
rc6e1892 r0f71490 3 3 import ArtistView from "./ArtistView"; 4 4 import ListenerView from "./ListenerView"; 5 6 interface MusicalEntityDTO { 7 id: number; 8 title: string; 9 genre: string; 10 type: string; 11 } 12 13 interface ArtistContributionDTO { 14 musicalEntityId: number; 15 title: string; 16 role: string; 17 entityType: string; 18 } 19 20 interface Playlist { 21 id: number; 22 name: string; 23 cover: string; 24 creatorName: string; 25 } 5 import axiosInstance from "../../api/axiosInstance"; 6 import type { ArtistContributionDTO } from "../../types"; 7 import type { MusicalEntityDTO } from "../../types"; 8 import type { Playlist } from "../../types"; 26 9 27 10 interface User { … … 32 15 followers: number; 33 16 following: number; 17 isFollowedByCurrentUser: boolean; 34 18 35 19 musicalEntities?: { … … 45 29 46 30 const UserDetail = () => { 31 // user refers to the selected user NOT to the user from context 47 32 const { userId } = useParams(); 48 33 const navigate = useNavigate(); … … 54 39 setError(null); 55 40 try { 56 const response = await fetch(`http://localhost:8080/users/${userId}`);41 const response = await axiosInstance.get(`/users/${userId}`); 57 42 58 if (!response.ok) { 59 const errorData = await response.json(); 60 throw new Error(errorData.error || "Failed to fetch user"); 61 } 62 63 const data = await response.json(); 64 setUser(data); 43 setUser(response.data); 65 44 } catch (err: any) { 66 setError(err.message); 45 const errorMessage = 46 err.response?.data?.error || "Failed to fetch user"; 47 setError(errorMessage); 67 48 } 68 49 }; … … 115 96 </div> 116 97 117 <button className="px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors font-medium">118 Follow98 <button className="px-6 py-2 bg-blue-500 hover:bg-blue-600 text-white font-semibold rounded-lg shadow-md transition-colors duration-200 cursor-pointer"> 99 {user.isFollowedByCurrentUser ? "Unfollow" : "Follow"} 119 100 </button> 120 101 </div> -
frontend/src/types.ts
rc6e1892 r0f71490 1 1 export interface User { 2 username: string;3 fullName: string;4 email?: string;5 profilePhoto?: string | null;6 role?: "ADMIN" | "NONADMIN";2 username: string; 3 fullName: string; 4 email?: string; 5 profilePhoto?: string | null; 6 role?: "ADMIN" | "NONADMIN"; 7 7 } 8 9 export interface ArtistContributionDTO { 10 musicalEntityId: number; 11 title: string; 12 genre: string; 13 role: string; 14 entityType: string; 15 } 16 export interface MusicalEntityDTO { 17 id: number; 18 title: string; 19 genre: string; 20 type: string; 21 } 22 23 export interface Playlist { 24 id: number; 25 name: string; 26 cover: string; 27 creatorName: string; 28 }
Note:
See TracChangeset
for help on using the changeset viewer.
