Skip to content

Commit

Permalink
Merge branch 'main' of github.com:mbaraa/dankmuzikk
Browse files Browse the repository at this point in the history
  • Loading branch information
mbaraa committed May 19, 2024
2 parents 4effbe8 + e0260f3 commit f75f519
Show file tree
Hide file tree
Showing 22 changed files with 283 additions and 158 deletions.
6 changes: 3 additions & 3 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ func StartServer(staticFS embed.FS) error {
songRepo := db.NewBaseDB[models.Song](dbConn)
playlistRepo := db.NewBaseDB[models.Playlist](dbConn)
playlistOwnersRepo := db.NewBaseDB[models.PlaylistOwner](dbConn)
playlistSongssRepo := db.NewBaseDB[models.PlaylistSong](dbConn)
playlistSongsRepo := db.NewBaseDB[models.PlaylistSong](dbConn)

downloadService := download.New(songRepo)
playlistsService := playlists.New(playlistRepo, playlistOwnersRepo, playlistSongssRepo, downloadService)
songsService := songs.New(playlistSongssRepo, songRepo, playlistRepo, downloadService)
playlistsService := playlists.New(playlistRepo, playlistOwnersRepo, playlistSongsRepo, downloadService)
songsService := songs.New(playlistSongsRepo, playlistOwnersRepo, songRepo, playlistRepo, downloadService)

jwtUtil := jwt.NewJWTImpl()

Expand Down
13 changes: 12 additions & 1 deletion handlers/apis/email_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,18 @@ func (e *emailLoginApi) HandleEmailOTPVerification(w http.ResponseWriter, r *htt
}

sessionToken, err := e.service.VerifyOtp(verificationToken.Value, reqBody)
// TODO: specify errors further suka
if errors.Is(err, login.ErrExpiredVerificationCode) {
status.
GenericError("Expired verification code!").
Render(context.Background(), w)
return
}
if errors.Is(err, login.ErrInvalidVerificationCode) {
status.
GenericError("Invalid verification code!").
Render(context.Background(), w)
return
}
if err != nil {
log.Error(err)
// w.WriteHeader(http.StatusInternalServerError)
Expand Down
6 changes: 3 additions & 3 deletions handlers/apis/playlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (p *playlistApi) HandleCreatePlaylist(w http.ResponseWriter, r *http.Reques
}

func (p *playlistApi) HandleToggleSongInPlaylist(w http.ResponseWriter, r *http.Request) {
_, profileIdCorrect := r.Context().Value(handlers.ProfileIdKey).(uint)
profileId, profileIdCorrect := r.Context().Value(handlers.ProfileIdKey).(uint)
if !profileIdCorrect {
w.Write([]byte("🤷‍♂️"))
return
Expand All @@ -78,9 +78,9 @@ func (p *playlistApi) HandleToggleSongInPlaylist(w http.ResponseWriter, r *http.
var err error
switch removeSongFromPlaylist {
case "false":
err = p.songService.AddSongToPlaylist(songId, playlistId)
err = p.songService.AddSongToPlaylist(songId, playlistId, profileId)
case "true":
err = p.songService.RemoveSongFromPlaylist(songId, playlistId)
err = p.songService.RemoveSongFromPlaylist(songId, playlistId, profileId)
}

if err != nil {
Expand Down
8 changes: 7 additions & 1 deletion handlers/apis/songs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package apis

import (
"dankmuzikk/entities"
"dankmuzikk/handlers"
"dankmuzikk/log"
"dankmuzikk/services/playlists/songs"
"dankmuzikk/services/youtube/download"
Expand All @@ -20,6 +21,11 @@ func NewDownloadHandler(service *download.Service, songsService *songs.Service)
}

func (s *songDownloadHandler) HandleIncrementSongPlaysInPlaylist(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)
Expand All @@ -31,7 +37,7 @@ func (s *songDownloadHandler) HandleIncrementSongPlaysInPlaylist(w http.Response
return
}

err := s.songsService.IncrementSongPlays(songId, playlistId)
err := s.songsService.IncrementSongPlays(songId, playlistId, profileId)
if err != nil {
log.Errorln(err)
w.WriteHeader(http.StatusInternalServerError)
Expand Down
10 changes: 3 additions & 7 deletions handlers/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ var noAuthPaths = []string{"/login", "/signup"}
// Handler is handler for pages and APIs, where it wraps the common stuff in one place.
type Handler struct {
profileRepo db.GORMDBGetter
jwtUtil jwt.Decoder[any]
jwtUtil jwt.Decoder[jwt.Json]
}

// NewHandler returns a new AuthHandler instance.
// Using a GORMDBGetter because this is supposed to be a light fetch,
// Where BaseDB doesn't provide column selection yet :(
func NewHandler(
accountRepo db.GORMDBGetter,
jwtUtil jwt.Decoder[any],
jwtUtil jwt.Decoder[jwt.Json],
) *Handler {
return &Handler{accountRepo, jwtUtil}
}
Expand Down Expand Up @@ -107,11 +107,7 @@ func (a *Handler) authenticate(r *http.Request) (entities.Profile, error) {
if err != nil {
return entities.Profile{}, err
}
payload, valid := theThing.Payload.(map[string]any)
if !valid || payload == nil {
return entities.Profile{}, err
}
username, validUsername := theThing.Payload.(map[string]any)["username"].(string)
username, validUsername := theThing.Payload["username"].(string)
if !validUsername || username == "" {
return entities.Profile{}, err
}
Expand Down
4 changes: 2 additions & 2 deletions handlers/pages/pages.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ const (
type pagesHandler struct {
profileRepo db.GetterRepo[models.Profile]
playlistsService *playlists.Service
jwtUtil jwt.Manager[any]
jwtUtil jwt.Manager[jwt.Json]
ytSearch search.Service
}

func NewPagesHandler(
profileRepo db.GetterRepo[models.Profile],
playlistsService *playlists.Service,
jwtUtil jwt.Manager[any],
jwtUtil jwt.Manager[jwt.Json],
ytSearch search.Service,
) *pagesHandler {
return &pagesHandler{
Expand Down
1 change: 0 additions & 1 deletion models/verification_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ type EmailVerificationCode struct {
Account Account
Code string `gorm:"not null"`
CreatedAt time.Time
UpdatedAt time.Time
}

func (e EmailVerificationCode) GetId() uint {
Expand Down
4 changes: 2 additions & 2 deletions services/jwt/jwt_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ type JWTImpl[T any] struct{}

// NewJWTImpl returns a new JWTImpl instance,
// and since session tokens are to validate users the working type is models.User
func NewJWTImpl() Manager[any] {
return &JWTImpl[any]{}
func NewJWTImpl() Manager[Json] {
return &JWTImpl[Json]{}
}

// Sign returns a JWT string(which will be the session token) based on the set JWT secret,
Expand Down
27 changes: 15 additions & 12 deletions services/login/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ type EmailLoginService struct {
accountRepo db.CRUDRepo[models.Account]
profileRepo db.CRUDRepo[models.Profile]
otpRepo db.CRUDRepo[models.EmailVerificationCode]
jwtUtil jwt.Manager[any]
jwtUtil jwt.Manager[jwt.Json]
}

func NewEmailLoginService(
accountRepo db.CRUDRepo[models.Account],
profileRepo db.CRUDRepo[models.Profile],
otpRepo db.CRUDRepo[models.EmailVerificationCode],
jwtUtil jwt.Manager[any],
jwtUtil jwt.Manager[jwt.Json],
) *EmailLoginService {
return &EmailLoginService{
accountRepo: accountRepo,
Expand All @@ -48,7 +48,7 @@ func (e *EmailLoginService) Login(user entities.LoginRequest) (string, error) {
profile[0].Account = account[0]
profile[0].AccountId = account[0].Id

verificationToken, err := e.jwtUtil.Sign(map[string]string{
verificationToken, err := e.jwtUtil.Sign(jwt.Json{
"name": profile[0].Name,
"email": profile[0].Account.Email,
"username": profile[0].Username,
Expand Down Expand Up @@ -78,7 +78,7 @@ func (e *EmailLoginService) Signup(user entities.SignupRequest) (string, error)
return "", err
}

verificationToken, err := e.jwtUtil.Sign(map[string]string{
verificationToken, err := e.jwtUtil.Sign(jwt.Json{
"name": profile.Name,
"email": profile.Account.Email,
"username": profile.Username,
Expand All @@ -91,23 +91,22 @@ func (e *EmailLoginService) Signup(user entities.SignupRequest) (string, error)
}

func (e *EmailLoginService) VerifyOtp(token string, otp entities.OtpRequest) (string, error) {
user, err := e.jwtUtil.Decode(token, jwt.VerificationToken)
tokeeeen, err := e.jwtUtil.Decode(token, jwt.VerificationToken)
if err != nil {
return "", err
}

mappedUser := user.Payload.(map[string]any)
email, emailExists := mappedUser["email"].(string)
email, emailExists := tokeeeen.Payload["email"].(string)
// TODO: ADD THE FUCKING ERRORS SUKA
if !emailExists {
return "", errors.New("missing email")
}
name, nameExists := mappedUser["name"].(string)
name, nameExists := tokeeeen.Payload["name"].(string)
// TODO: ADD THE FUCKING ERRORS SUKA
if !nameExists {
return "", errors.New("missing name")
}
username, usernameExists := mappedUser["username"].(string)
username, usernameExists := tokeeeen.Payload["username"].(string)
// TODO: ADD THE FUCKING ERRORS SUKA
if !usernameExists {
return "", errors.New("missing username")
Expand All @@ -124,15 +123,19 @@ func (e *EmailLoginService) VerifyOtp(token string, otp entities.OtpRequest) (st
}
verCode := verCodes[len(verCodes)-1]
defer func() {
_ = e.otpRepo.Delete("id = ?", verCode.Id)
_ = e.otpRepo.Delete("account_id = ?", account[0].Id)
}()

if verCode.CreatedAt.Add(time.Hour / 2).Before(time.Now()) {
return "", ErrExpiredVerificationCode
}

err = bcrypt.CompareHashAndPassword([]byte(verCode.Code), []byte(otp.Code))
if err != nil {
return "", err
return "", ErrInvalidVerificationCode
}

sessionToken, err := e.jwtUtil.Sign(map[string]string{
sessionToken, err := e.jwtUtil.Sign(jwt.Json{
"email": email,
"name": name,
"username": username,
Expand Down
8 changes: 5 additions & 3 deletions services/login/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package login
import "errors"

var (
ErrAccountNotFound = errors.New("account was not found")
ErrProfileNotFound = errors.New("profile was not found")
ErrAccountExists = errors.New("an account with the associated email already exists")
ErrAccountNotFound = errors.New("account was not found")
ErrProfileNotFound = errors.New("profile was not found")
ErrAccountExists = errors.New("an account with the associated email already exists")
ErrExpiredVerificationCode = errors.New("expired verification code")
ErrInvalidVerificationCode = errors.New("invalid verification code")
)
8 changes: 4 additions & 4 deletions services/login/google.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ type GoogleLoginService struct {
accountRepo db.CRUDRepo[models.Account]
profileRepo db.CRUDRepo[models.Profile]
otpRepo db.CRUDRepo[models.EmailVerificationCode]
jwtUtil jwt.Manager[any]
jwtUtil jwt.Manager[jwt.Json]
}

func NewGoogleLoginService(
accountRepo db.CRUDRepo[models.Account],
profileRepo db.CRUDRepo[models.Profile],
otpRepo db.CRUDRepo[models.EmailVerificationCode],
jwtUtil jwt.Manager[any],
jwtUtil jwt.Manager[jwt.Json],
) *GoogleLoginService {
return &GoogleLoginService{
accountRepo: accountRepo,
Expand Down Expand Up @@ -79,7 +79,7 @@ func (g *GoogleLoginService) Login(state, code string) (string, error) {
profile[0].Account = account[0]
profile[0].AccountId = account[0].Id

verificationToken, err := g.jwtUtil.Sign(map[string]string{
verificationToken, err := g.jwtUtil.Sign(jwt.Json{
"name": profile[0].Name,
"email": profile[0].Account.Email,
"username": profile[0].Username,
Expand Down Expand Up @@ -107,7 +107,7 @@ func (g *GoogleLoginService) Signup(googleUser oauthUserInfo) (string, error) {
return "", err
}

verificationToken, err := g.jwtUtil.Sign(map[string]string{
verificationToken, err := g.jwtUtil.Sign(jwt.Json{
"name": profile.Name,
"email": profile.Account.Email,
"username": profile.Username,
Expand Down
58 changes: 22 additions & 36 deletions services/playlists/playlists.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ func (p *Service) Get(playlistPubId string, ownerId uint) (entities.Playlist, er
Id: ownerId,
}).
Where("public_id = ?", playlistPubId).
Preload("Songs").
Association("Playlist").
Find(&dbPlaylists)
if err != nil {
Expand All @@ -148,46 +147,33 @@ func (p *Service) Get(playlistPubId string, ownerId uint) (entities.Playlist, er
return entities.Playlist{}, ErrUnauthorizedToSeePlaylist
}

var playlistSongs []models.PlaylistSong
err = p.
playlistSongsRepo.
gigaQuery := `SELECT yt_id, title, artist, thumbnail_url, duration, ps.created_at, ps.play_times
FROM
playlist_owners po JOIN playlist_songs ps ON po.playlist_id = ps.playlist_id
JOIN songs
ON ps.song_id = songs.id
WHERE ps.playlist_id = ? AND po.profile_id = ?
ORDER BY ps.created_at;`

rows, err := p.repo.
GetDB().
Model(new(models.PlaylistSong)).
Where("playlist_id = ?", dbPlaylists[0].Id).
Select("song_id", "play_times", "votes", "created_at").
Find(&playlistSongs).
Error
Raw(gigaQuery, dbPlaylists[0].Id, ownerId).
Rows()
if err != nil {
return entities.Playlist{
PublicId: dbPlaylists[0].PublicId,
Title: dbPlaylists[0].Title,
}, err
}
if len(playlistSongs) == 0 {
return entities.Playlist{
PublicId: dbPlaylists[0].PublicId,
Title: dbPlaylists[0].Title,
}, ErrEmptyPlaylist
}

mappedPlaylistSongsToPlaysSuka := make(map[uint]int)
mappedPlaylistSongsToCreatedAtSuka := make(map[uint]time.Time)
for _, playlistSong := range playlistSongs {
mappedPlaylistSongsToPlaysSuka[playlistSong.SongId] = playlistSong.PlayTimes
mappedPlaylistSongsToCreatedAtSuka[playlistSong.SongId] = playlistSong.CreatedAt
return entities.Playlist{}, err
}
defer rows.Close()

songs := make([]entities.Song, len(dbPlaylists[0].Songs))
for i, song := range dbPlaylists[0].Songs {
songs[i] = entities.Song{
YtId: song.YtId,
Title: song.Title,
Artist: song.Artist,
ThumbnailUrl: song.ThumbnailUrl,
Duration: song.Duration,
PlayTimes: mappedPlaylistSongsToPlaysSuka[song.Id],
AddedAt: mappedPlaylistSongsToCreatedAtSuka[song.Id].Format("2, January, 2006"),
songs := make([]entities.Song, 0)
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)
if err != nil {
continue
}
song.AddedAt = addedAt.Format("2, January, 2006")
songs = append(songs, song)
}

return entities.Playlist{
Expand Down
Loading

0 comments on commit f75f519

Please sign in to comment.