Skip to content

Commit

Permalink
Merge pull request #57 from mbaraa/feat/vote-songs-in-playlist
Browse files Browse the repository at this point in the history
Feat: Vote Songs in Playlists
  • Loading branch information
mbaraa authored May 27, 2024
2 parents 8d91881 + 52fb70a commit 548a25f
Show file tree
Hide file tree
Showing 12 changed files with 423 additions and 70 deletions.
1 change: 1 addition & 0 deletions cmd/migrator/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func Migrate() error {
new(models.PlaylistSong),
new(models.PlaylistOwner),
new(models.History),
new(models.PlaylistSongVoter),
)
if err != nil {
return err
Expand Down
11 changes: 7 additions & 4 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ func StartServer(staticFS embed.FS) error {
playlistOwnersRepo := db.NewBaseDB[models.PlaylistOwner](dbConn)
playlistSongsRepo := db.NewBaseDB[models.PlaylistSong](dbConn)
historyRepo := db.NewBaseDB[models.History](dbConn)
playlistVotersRepo := db.NewBaseDB[models.PlaylistSongVoter](dbConn)

downloadService := download.New(songRepo)
playlistsService := playlists.New(playlistRepo, playlistOwnersRepo, playlistSongsRepo)
songsService := songs.New(playlistSongsRepo, playlistOwnersRepo, songRepo, playlistRepo, downloadService)
songsService := songs.New(playlistSongsRepo, playlistOwnersRepo, songRepo, playlistRepo, playlistVotersRepo, downloadService)
historyService := history.New(historyRepo, songRepo)

jwtUtil := jwt.NewJWTImpl()
Expand Down Expand Up @@ -85,7 +86,7 @@ func StartServer(staticFS embed.FS) error {

emailLoginApi := apis.NewEmailLoginApi(login.NewEmailLoginService(accountRepo, profileRepo, otpRepo, jwtUtil))
googleLoginApi := apis.NewGoogleLoginApi(login.NewGoogleLoginService(accountRepo, profileRepo, otpRepo, jwtUtil))
songDownloadApi := apis.NewDownloadHandler(downloadService, songsService, historyService)
songApi := apis.NewDownloadHandler(downloadService, songsService, historyService)
playlistsApi := apis.NewPlaylistApi(playlistsService, songsService)
historyApi := apis.NewHistoryApi(historyService)

Expand All @@ -98,9 +99,11 @@ func StartServer(staticFS embed.FS) error {
apisHandler.HandleFunc("/login/google/callback", googleLoginApi.HandleGoogleOAuthLoginCallback)
apisHandler.HandleFunc("GET /logout", apis.HandleLogout)
apisHandler.HandleFunc("GET /search-suggestion", apis.HandleSearchSuggestions)
apisHandler.HandleFunc("GET /song", gHandler.OptionalAuthApi(songDownloadApi.HandlePlaySong))
apisHandler.HandleFunc("GET /song", gHandler.OptionalAuthApi(songApi.HandlePlaySong))
apisHandler.HandleFunc("PUT /song/playlist", gHandler.AuthApi(playlistsApi.HandleToggleSongInPlaylist))
apisHandler.HandleFunc("PUT /song/playlist/plays", gHandler.AuthApi(songDownloadApi.HandleIncrementSongPlaysInPlaylist))
apisHandler.HandleFunc("PUT /song/playlist/plays", gHandler.AuthApi(songApi.HandleIncrementSongPlaysInPlaylist))
apisHandler.HandleFunc("PUT /song/playlist/upvote", gHandler.AuthApi(songApi.HandleUpvoteSongPlaysInPlaylist))
apisHandler.HandleFunc("PUT /song/playlist/downvote", gHandler.AuthApi(songApi.HandleDownvoteSongPlaysInPlaylist))
apisHandler.HandleFunc("GET /playlist/all", gHandler.AuthApi(playlistsApi.HandleGetPlaylistsForPopover))
apisHandler.HandleFunc("POST /playlist", gHandler.AuthApi(playlistsApi.HandleCreatePlaylist))
apisHandler.HandleFunc("PUT /playlist/public", gHandler.AuthApi(playlistsApi.HandleTogglePublicPlaylist))
Expand Down
2 changes: 1 addition & 1 deletion db/allowed_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import "dankmuzikk/models"
type AllowedModels interface {
models.Account | models.Profile | models.EmailVerificationCode |
models.Song | models.Playlist | models.PlaylistSong | models.PlaylistOwner |
models.History
models.History | models.PlaylistSongVoter
GetId() uint
}
1 change: 1 addition & 0 deletions entities/song.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ type Song struct {
ThumbnailUrl string `json:"thumbnail_url"`
Duration string `json:"duration"`
PlayTimes int `json:"play_times"`
Votes int `json:"votes"`
AddedAt string `json:"added_at"`
}
55 changes: 55 additions & 0 deletions handlers/apis/songs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"dankmuzikk/services/history"
"dankmuzikk/services/playlists/songs"
"dankmuzikk/services/youtube/download"
"fmt"
"net/http"
)

Expand Down Expand Up @@ -52,6 +53,60 @@ func (s *songDownloadHandler) HandleIncrementSongPlaysInPlaylist(w http.Response
}
}

func (s *songDownloadHandler) HandleUpvoteSongPlaysInPlaylist(w http.ResponseWriter, r *http.Request) {
profileId, profileIdCorrect := r.Context().Value(handlers.ProfileIdKey).(uint)
if !profileIdCorrect {
w.Write([]byte("🤷‍♂️"))
return
}
songId := r.URL.Query().Get("song-id")
if songId == "" {
w.WriteHeader(http.StatusBadRequest)
return
}
playlistId := r.URL.Query().Get("playlist-id")
if playlistId == "" {
w.WriteHeader(http.StatusBadRequest)
return
}

votes, err := s.songsService.UpvoteSong(songId, playlistId, profileId)
if err != nil {
log.Errorln(err)
w.WriteHeader(http.StatusInternalServerError)
return
}

_, _ = w.Write([]byte(fmt.Sprint(votes)))
}

func (s *songDownloadHandler) HandleDownvoteSongPlaysInPlaylist(w http.ResponseWriter, r *http.Request) {
profileId, profileIdCorrect := r.Context().Value(handlers.ProfileIdKey).(uint)
if !profileIdCorrect {
w.Write([]byte("🤷‍♂️"))
return
}
songId := r.URL.Query().Get("song-id")
if songId == "" {
w.WriteHeader(http.StatusBadRequest)
return
}
playlistId := r.URL.Query().Get("playlist-id")
if playlistId == "" {
w.WriteHeader(http.StatusBadRequest)
return
}

votes, err := s.songsService.DownvoteSong(songId, playlistId, profileId)
if err != nil {
log.Errorln(err)
w.WriteHeader(http.StatusInternalServerError)
return
}

_, _ = w.Write([]byte(fmt.Sprint(votes)))
}

func (s *songDownloadHandler) HandlePlaySong(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
if id == "" {
Expand Down
24 changes: 23 additions & 1 deletion models/playlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,18 @@ func (p *PlaylistSong) BeforeDelete(tx *gorm.DB) error {
return err
}

return tx.
err = tx.
Model(&playlist).
Where("id = ?", p.PlaylistId).
Update("songs_count", playlist.SongsCount-1).
Error
if err != nil {
return err
}

return tx.
Exec("DELETE FROM playlist_song_voters WHERE playlist_id = ? AND song_id = ?", p.PlaylistId, p.SongId).
Error
}

type PlaylistOwner struct {
Expand All @@ -114,3 +121,18 @@ const (
OwnerPermission
NonePermission PlaylistPermissions = 0
)

// PlaylistSongVoter ensures that an account had voted only once.
type PlaylistSongVoter struct {
PlaylistId uint `gorm:"primaryKey"`
SongId uint `gorm:"primaryKey"`
ProfileId uint `gorm:"primaryKey"`
VoteUp bool

CreatedAt time.Time
UpdatedAt time.Time
}

func (p PlaylistSongVoter) GetId() uint {
return p.SongId | p.PlaylistId | p.ProfileId
}
1 change: 1 addition & 0 deletions services/playlists/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ var (
ErrNonOwnerCantDeletePlaylists = errors.New("playlists: non owners can only leave playlists")
ErrUnauthorizedToSeePlaylist = errors.New("playlists: unauthorized to see playlist")
ErrEmptyPlaylist = errors.New("playlists: empty playlists")
ErrUserHasAlreadyVoted = errors.New("playlist: user can't vote more than once")
)
4 changes: 2 additions & 2 deletions services/playlists/playlists.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (p *Service) Get(playlistPubId string, ownerId uint) (playlist entities.Pla
return entities.Playlist{}, models.NonePermission, ErrUnauthorizedToSeePlaylist
}

gigaQuery := `SELECT yt_id, title, artist, thumbnail_url, duration, ps.created_at, ps.play_times
gigaQuery := `SELECT yt_id, title, artist, thumbnail_url, duration, ps.created_at, ps.play_times, ps.votes
FROM
playlist_songs ps
JOIN songs
Expand All @@ -152,7 +152,7 @@ func (p *Service) Get(playlistPubId string, ownerId uint) (playlist entities.Pla
for rows.Next() {
var song entities.Song
var addedAt time.Time
err = rows.Scan(&song.YtId, &song.Title, &song.Artist, &song.ThumbnailUrl, &song.Duration, &addedAt, &song.PlayTimes)
err = rows.Scan(&song.YtId, &song.Title, &song.Artist, &song.ThumbnailUrl, &song.Duration, &addedAt, &song.PlayTimes, &song.Votes)
if err != nil {
continue
}
Expand Down
Loading

0 comments on commit 548a25f

Please sign in to comment.