Migrating to postgresql

This commit is contained in:
Daniel Mason 2021-12-25 22:24:47 +13:00
parent 97a6087e42
commit 6c52aa7d78
47 changed files with 332 additions and 308 deletions

View file

@ -73,7 +73,7 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, i
func getAlbumByCol(col string, val string, tx *sql.Tx) Album {
var album Album
err := tx.QueryRow(
"SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`, ''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `albums` WHERE `"+col+"` = ?",
"SELECT uuid, name, IFNULL(desc, ''), IFNULL(img,''), mbid, spotify_id FROM albums WHERE "+col+" = $1",
val).Scan(&album.UUID, &album.Name, &album.Desc, &album.Img, &album.MusicBrainzID, &album.SpotifyID)
if err != nil {
@ -92,8 +92,8 @@ func insertNewAlbum(album *Album, name string, mbid string, spotifyId string, im
album.SpotifyID = spotifyId
album.Img = img
_, err := tx.Exec("INSERT INTO `albums` (`uuid`, `name`, `mbid`, `spotify_id`, `img`) "+
"VALUES (UUID_TO_BIN(?, true),?,?,?,?)", album.UUID, album.Name, album.MusicBrainzID, album.SpotifyID, album.Img)
_, err := tx.Exec("INSERT INTO albums (uuid, name, mbid, spotify_id, img) "+
"VALUES ($1,$2,$3,$4,$5)", album.UUID, album.Name, album.MusicBrainzID, album.SpotifyID, album.Img)
return err
}
@ -101,8 +101,8 @@ func insertNewAlbum(album *Album, name string, mbid string, spotifyId string, im
func (album *Album) linkAlbumToArtists(artists []string, tx *sql.Tx) error {
var err error
for _, artist := range artists {
_, err = tx.Exec("INSERT INTO `album_artist` (`album`, `artist`) "+
"VALUES (UUID_TO_BIN(?, true), UUID_TO_BIN(?, true))", album.UUID, artist)
_, err = tx.Exec("INSERT INTO album_artist (album, artist) "+
"VALUES ($1,$2)", album.UUID, artist)
if err != nil {
return err
}
@ -112,14 +112,14 @@ func (album *Album) linkAlbumToArtists(artists []string, tx *sql.Tx) error {
}
func (album *Album) updateAlbum(col string, val string, tx *sql.Tx) error {
_, err := tx.Exec("UPDATE `albums` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, album.UUID)
_, err := tx.Exec("UPDATE albums SET "+col+" = $1 WHERE uuid = $2", val, album.UUID)
return err
}
func getAlbumByUUID(uuid string) (Album, error) {
var album Album
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `albums` WHERE `uuid` = UUID_TO_BIN(?, true)",
err := db.QueryRow("SELECT uuid, name, IFNULL(desc,''), IFNULL(img,''), mbid, spotify_id FROM albums WHERE uuid = $1",
uuid).Scan(&album.UUID, &album.Name, &album.Desc, &album.Img, &album.MusicBrainzID, &album.SpotifyID)
if err != nil {

View file

@ -83,7 +83,7 @@ func insertArtist(name string, mbid string, spotifyId string, img string, tx *sq
func getArtistByCol(col string, val string, tx *sql.Tx) Artist {
var artist Artist
err := tx.QueryRow(
"SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `artists` WHERE `"+col+"` = ?",
"SELECT uuid, name, IFNULL(desc,''), IFNULL(img,''), mbid, spotify_id FROM artists WHERE "+col+" = $1",
val).Scan(&artist.UUID, &artist.Name, &artist.Desc, &artist.Img, &artist.MusicBrainzID, &artist.SpotifyID)
if err != nil {
@ -102,21 +102,21 @@ func insertNewArtist(artist *Artist, name string, mbid string, spotifyId string,
artist.SpotifyID = spotifyId
artist.Img = img
_, err := tx.Exec("INSERT INTO `artists` (`uuid`, `name`, `mbid`, `spotify_id`, `img`) "+
"VALUES (UUID_TO_BIN(?, true),?,?,?,?)", artist.UUID, artist.Name, artist.MusicBrainzID, artist.SpotifyID, artist.Img)
_, err := tx.Exec("INSERT INTO artists (uuid, name, mbid, spotify_id, img) "+
"VALUES ($1,$2,$3,$4,$5)", artist.UUID, artist.Name, artist.MusicBrainzID, artist.SpotifyID, artist.Img)
return err
}
func (artist *Artist) updateArtist(col string, val string, tx *sql.Tx) error {
_, err := tx.Exec("UPDATE `artists` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, artist.UUID)
_, err := tx.Exec("UPDATE artists SET "+col+" = $1 WHERE uuid = $2", val, artist.UUID)
return err
}
func getArtistByUUID(uuid string) (Artist, error) {
var artist Artist
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`, ''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `artists` WHERE `uuid` = UUID_TO_BIN(?, true)",
err := db.QueryRow("SELECT uuid, name, IFNULL(desc, ''), IFNULL(img,''), mbid, spotify_id FROM artists WHERE uuid = $1",
uuid).Scan(&artist.UUID, &artist.Name, &artist.Desc, &artist.Img, &artist.MusicBrainzID, &artist.SpotifyID)
if err == sql.ErrNoRows {
@ -129,13 +129,13 @@ func getArtistByUUID(uuid string) (Artist, error) {
func getTopArtists(userUuid string) (TopArtists, error) {
var topArtist TopArtists
rows, err := db.Query("SELECT BIN_TO_UUID(`artists`.`uuid`, true), `artists`.`name`, IFNULL(BIN_TO_UUID(`artists`.`uuid`, true),''), count(*) "+
"FROM `scrobbles` "+
"JOIN `tracks` ON `tracks`.`uuid` = `scrobbles`.`track` "+
rows, err := db.Query("SELECT artists.uuid, artists.name, IFNULL(artists.uuid,''), count(*) "+
"FROM scrobbles "+
"JOIN tracks ON tracks.uuid = scrobbles.track "+
"JOIN track_artist ON track_artist.track = tracks.uuid "+
"JOIN artists ON track_artist.artist = artists.uuid "+
"WHERE `scrobbles`.`user` = UUID_TO_BIN(?, true) "+
"GROUP BY `artists`.`uuid` "+
"WHERE scrobbles.user = $1 "+
"GROUP BY artists.uuid "+
"ORDER BY count(*) DESC "+
"LIMIT 14;",
userUuid)

View file

@ -20,7 +20,7 @@ func getAllConfigs() (Config, error) {
config := Config{}
configs := make(map[string]string)
rows, err := db.Query("SELECT `key`, `value` FROM `config`")
rows, err := db.Query("SELECT key, value FROM config")
if err != nil {
log.Printf("Failed to fetch config: %+v", err)
return config, errors.New("Failed to fetch configs")
@ -53,7 +53,7 @@ func getAllConfigs() (Config, error) {
}
func updateConfigValue(key string, value string) error {
_, err := db.Exec("UPDATE `config` SET `value` = ? WHERE `key` = ?", value, key)
_, err := db.Exec("UPDATE config SET value = $1 WHERE key = $2", value, key)
if err != nil {
fmt.Printf("Failed to update config: %+v", err)
return errors.New("Failed to update config value.")
@ -65,8 +65,8 @@ func updateConfigValue(key string, value string) error {
func getConfigValue(key string) (string, error) {
var value string
err := db.QueryRow("SELECT `value` FROM `config` "+
"WHERE `key` = ?",
err := db.QueryRow("SELECT value FROM config "+
"WHERE key = $1",
key).Scan(&value)
if err == sql.ErrNoRows {

View file

@ -8,22 +8,26 @@ import (
"os"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database/mysql"
"github.com/golang-migrate/migrate/database/postgres"
_ "github.com/golang-migrate/migrate/source/file"
_ "github.com/lib/pq"
)
var db *sql.DB
// InitDb - Boots up a DB connection
func InitDb() {
dbHost := os.Getenv("MYSQL_HOST")
dbUser := os.Getenv("MYSQL_USER")
dbPass := os.Getenv("MYSQL_PASS")
dbName := os.Getenv("MYSQL_DB")
dbHost := os.Getenv("POSTGRES_HOST")
dbUser := os.Getenv("POSTGRES_USER")
dbPass := os.Getenv("POSTGRES_PASS")
dbName := os.Getenv("POSTGRES_DB")
dbConn, err := sql.Open(
"postgres",
fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", dbHost, 5432, dbUser, dbPass, dbName),
)
dbConn, err := sql.Open("mysql", dbUser+":"+dbPass+"@tcp("+dbHost+")/"+dbName+"?multiStatements=true&parseTime=true&loc=Etc%2FUTC")
if err != nil {
panic(err)
}
@ -49,14 +53,14 @@ func CloseDbConn() {
func runMigrations() {
fmt.Println("Checking database migrations")
driver, err := mysql.WithInstance(db, &mysql.Config{})
driver, err := postgres.WithInstance(db, &postgres.Config{})
if err != nil {
log.Fatalf("Unable to run migrations! %v", err)
}
m, err := migrate.NewWithDatabaseInstance(
"file://migrations",
"mysql",
"postgres",
driver,
)
if err != nil {

View file

@ -13,7 +13,7 @@ type Genre struct {
func getGenreByUUID(uuid string) Genre {
var genre Genre
err := db.QueryRow(
"SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `artists` WHERE `uuid` = UUID_TO_BIN(?,true)",
"SELECT uuid, name FROM artists WHERE uuid = $1",
uuid).Scan(&genre.UUID, &genre.Name)
if err != nil {
@ -28,7 +28,7 @@ func getGenreByUUID(uuid string) Genre {
func getGenreByName(name string) Genre {
var genre Genre
err := db.QueryRow(
"SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `artists` WHERE `name` = ?",
"SELECT uuid, name FROM artists WHERE name = $1",
name).Scan(&genre.UUID, &genre.Name)
if err != nil {
@ -41,7 +41,7 @@ func getGenreByName(name string) Genre {
}
func (genre *Genre) updateGenreName(name string, value string) error {
_, err := db.Exec("UPDATE `genres` SET `name` = ? WHERE uuid = UUID_TO_BIN(?, true)", name, genre.UUID)
_, err := db.Exec("UPDATE genres SET name = $1 WHERE uuid = $2", name, genre.UUID)
return err
}

View file

@ -238,7 +238,7 @@ func (user *User) updateImageDataFromSpotify() error {
client := auth.NewClient(token)
client.AutoRetry = true
rows, err := db.Query("SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `artists` WHERE IFNULL(`img`,'') NOT IN ('pending', 'complete') LIMIT 100")
rows, err := db.Query("SELECT uuid, name FROM artists WHERE IFNULL(img,'') NOT IN ('pending', 'complete') LIMIT 100")
if err != nil {
log.Printf("Failed to fetch config: %+v", err)
return errors.New("Failed to fetch artists")
@ -282,7 +282,7 @@ func (user *User) updateImageDataFromSpotify() error {
}
tx.Commit()
rows, err = db.Query("SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `albums` WHERE IFNULL(`img`,'') NOT IN ('pending', 'complete') LIMIT 100")
rows, err = db.Query("SELECT uuid, name FROM albums WHERE IFNULL(img,'') NOT IN ('pending', 'complete') LIMIT 100")
if err != nil {
log.Printf("Failed to fetch config: %+v", err)
return errors.New("Failed to fetch artists")

View file

@ -20,8 +20,8 @@ type OauthToken struct {
func getOauthToken(userUuid string, service string) (OauthToken, error) {
var oauth OauthToken
err := db.QueryRow("SELECT BIN_TO_UUID(`user`, true), `service`, `access_token`, `refresh_token`, `expiry`, `username`, `last_synced`, `url` FROM `oauth_tokens` "+
"WHERE `user` = UUID_TO_BIN(?, true) AND `service` = ?",
err := db.QueryRow("SELECT user, service, access_token, refresh_token, expiry, username, last_synced, url FROM oauth_tokens "+
"WHERE user = $1 AND service = $2",
userUuid, service).Scan(&oauth.UserUUID, &oauth.Service, &oauth.AccessToken, &oauth.RefreshToken, &oauth.Expiry, &oauth.Username, &oauth.LastSynced, &oauth.URL)
if err == sql.ErrNoRows {
@ -32,14 +32,14 @@ func getOauthToken(userUuid string, service string) (OauthToken, error) {
}
func insertOauthToken(userUuid string, service string, token string, refresh string, expiry time.Time, username string, lastSynced time.Time, url string) error {
_, err := db.Exec("REPLACE INTO `oauth_tokens` (`user`, `service`, `access_token`, `refresh_token`, `expiry`, `username`, `last_synced`, `url`) "+
"VALUES (UUID_TO_BIN(?, true),?,?,?,?,?,?,?)", userUuid, service, token, refresh, expiry, username, lastSynced, url)
_, err := db.Exec("REPLACE INTO oauth_tokens (user, service, access_token, refresh_token, expiry, username, last_synced, url) "+
"VALUES ($1,$2,$3,$4,$5,$6,$7,$8)", userUuid, service, token, refresh, expiry, username, lastSynced, url)
return err
}
func removeOauthToken(userUuid string, service string) error {
_, err := db.Exec("DELETE FROM `oauth_tokens` WHERE `user` = UUID_TO_BIN(?, true) AND `service` = ?", userUuid, service)
_, err := db.Exec("DELETE FROM oauth_tokens WHERE user = $1 AND service = $2", userUuid, service)
return err
}

View file

@ -59,7 +59,7 @@ func getScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse
// Yeah this isn't great. But for now.. it works! Cache later
total, err := getDbCount(
"SELECT COUNT(*) FROM `scrobbles` WHERE `user` = UUID_TO_BIN(?, true) ", userUuid)
"SELECT COUNT(*) FROM scrobbles WHERE user = $1", userUuid)
if err != nil {
log.Printf("Failed to fetch scrobble count: %+v", err)
@ -67,16 +67,16 @@ func getScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse
}
rows, err := db.Query(
"SELECT BIN_TO_UUID(`scrobbles`.`uuid`, true), `scrobbles`.`created_at`, BIN_TO_UUID(`artists`.`uuid`, true), `artists`.`name`, `albums`.`name`, BIN_TO_UUID(`tracks`.`uuid`, true), `tracks`.`name`, `scrobbles`.`source` FROM `scrobbles` "+
"SELECT scrobbles.uuid, scrobbles.created_at, artists.uuid, artists.name, albums.name, tracks.uuid, tracks.name, scrobbles.source FROM scrobbles "+
"JOIN tracks ON scrobbles.track = tracks.uuid "+
"JOIN track_artist ON track_artist.track = tracks.uuid "+
"JOIN track_album ON track_album.track = tracks.uuid "+
"JOIN artists ON track_artist.artist = artists.uuid "+
"JOIN albums ON track_album.album = albums.uuid "+
"JOIN users ON scrobbles.user = users.uuid "+
"WHERE user = UUID_TO_BIN(?, true) "+
"WHERE user = $1 "+
"GROUP BY scrobbles.uuid, albums.uuid "+
"ORDER BY scrobbles.created_at DESC LIMIT ?",
"ORDER BY scrobbles.created_at DESC LIMIT $2",
userUuid, limit)
if err != nil {
@ -110,14 +110,14 @@ func getScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse
}
func insertNewScrobble(user string, track string, source string, timestamp time.Time, ip net.IP, tx *sql.Tx) error {
_, err := tx.Exec("INSERT INTO `scrobbles` (`uuid`, `created_at`, `created_ip`, `user`, `track`, `source`) "+
"VALUES (UUID_TO_BIN(?, true), ?, ?, UUID_TO_BIN(?, true), UUID_TO_BIN(?, true), ?)", newUUID(), timestamp, ip, user, track, source)
_, err := tx.Exec(`INSERT INTO scrobbles (uuid, created_at, created_ip, "user", track, source) `+
`VALUES ($1,$2,$3,$4,$5,$6)`, newUUID(), timestamp, ip.String(), user, track, source)
return err
}
func checkIfScrobbleExists(userUuid string, timestamp time.Time, source string) bool {
count, err := getDbCount("SELECT COUNT(*) FROM `scrobbles` WHERE `user` = UUID_TO_BIN(?, true) AND `created_at` = ? AND `source` = ?",
count, err := getDbCount(`SELECT COUNT(*) FROM scrobbles WHERE "user" = $1 AND created_at = $2 AND source = $3`,
userUuid, timestamp, source)
if err != nil {

View file

@ -53,25 +53,25 @@ func getAllStats() (StatsRequest, error) {
statsReq := StatsRequest{}
var err error
statsReq.Users, err = getDbCount("SELECT COUNT(*) FROM `users` WHERE `active` = 1")
statsReq.Users, err = getDbCount("SELECT COUNT(*) FROM users WHERE active = true")
if err != nil {
log.Printf("Failed to fetch user count: %+v", err)
return statsReq, errors.New("Failed to fetch stats")
}
statsReq.Scrobbles, err = getDbCount("SELECT COUNT(*) FROM `scrobbles`")
statsReq.Scrobbles, err = getDbCount("SELECT COUNT(*) FROM scrobbles")
if err != nil {
log.Printf("Failed to fetch scrobble count: %+v", err)
return statsReq, errors.New("Failed to fetch stats")
}
statsReq.Tracks, err = getDbCount("SELECT COUNT(*) FROM `tracks`")
statsReq.Tracks, err = getDbCount("SELECT COUNT(*) FROM tracks")
if err != nil {
log.Printf("Failed to fetch track count: %+v", err)
return statsReq, errors.New("Failed to fetch stats")
}
statsReq.Artists, err = getDbCount("SELECT COUNT(*) FROM `artists`")
statsReq.Artists, err = getDbCount("SELECT COUNT(*) FROM artists")
if err != nil {
log.Printf("Failed to fetch artist count: %+v", err)
return statsReq, errors.New("Failed to fetch stats")

View file

@ -29,7 +29,7 @@ func getUserUuidForToken(token string) (string, error) {
var uuid string
cachedKey := getRedisVal("user_token:" + token)
if cachedKey == "" {
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true) FROM `users` WHERE `token` = ? AND `active` = 1", token).Scan(&uuid)
err := db.QueryRow("SELECT uuid FROM users WHERE token = $1 AND active = true", token).Scan(&uuid)
if err != nil {
return "", errors.New("Invalid Token")
}
@ -43,21 +43,21 @@ func getUserUuidForToken(token string) (string, error) {
func insertRefreshToken(userUuid string, token string) error {
uuid := newUUID()
_, err := db.Exec("INSERT INTO `refresh_tokens` (`uuid`, `user`, `token`) VALUES (UUID_TO_BIN(?,true),UUID_TO_BIN(?,true),?)",
_, err := db.Exec(`INSERT INTO refresh_tokens (uuid, "user", token) VALUES ($1,$2,$3)`,
uuid, userUuid, token)
return err
}
func deleteRefreshToken(token string) error {
_, err := db.Exec("DELETE FROM `refresh_tokens` WHERE `token` = ?", token)
_, err := db.Exec("DELETE FROM refresh_tokens WHERE token = $1", token)
return err
}
func isValidRefreshToken(refreshTokenStr string) (User, error) {
var refresh RefreshToken
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), BIN_TO_UUID(`user`, true), `token`, `expiry` FROM `refresh_tokens` WHERE `token` = ?",
err := db.QueryRow("SELECT uuid, user, token, expiry FROM refresh_tokens WHERE token = $1",
refreshTokenStr).Scan(&refresh.UUID, &refresh.User, &refresh.Token, &refresh.Expiry)
if err != nil {
return User{}, errors.New("Invalid Refresh Token")

View file

@ -98,7 +98,7 @@ func insertTrack(name string, legnth int, mbid string, spotifyId string, album s
func getTrackByCol(col string, val string, tx *sql.Tx) Track {
var track Track
err := tx.QueryRow(
"SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid` FROM `tracks` WHERE `"+col+"` = ? LIMIT 1",
"SELECT uuid, name, IFNULL(desc,''), IFNULL(img,''), mbid FROM tracks WHERE "+col+" = $1 LIMIT 1",
val).Scan(&track.UUID, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID)
if err != nil {
@ -114,11 +114,11 @@ func getTrackWithArtists(name string, artists []string, album string, tx *sql.Tx
var track Track
artistString := strings.Join(artists, "','")
err := tx.QueryRow(
"SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid` FROM `tracks` "+
"LEFT JOIN `track_artist` ON `tracks`.`uuid` = `track_artist`.`track` "+
"LEFT JOIN `track_album` ON `tracks`.`uuid` = `track_album`.`track` "+
"WHERE `name` = ? AND BIN_TO_UUID(`track_artist`.`artist`, true) IN ('"+artistString+"') "+
"AND BIN_TO_UUID(`track_album`.`album`,true) = ? LIMIT 1",
"SELECT uuid, name, IFNULL(desc,''), IFNULL(img,''), mbid FROM tracks "+
"LEFT JOIN track_artist ON tracks.uuid = track_artist.track "+
"LEFT JOIN track_album ON tracks.uuid = track_album.track "+
"WHERE name = $1 AND track_artist.artistIN ('"+artistString+"') "+
"AND track_album.album = $2 LIMIT 1",
name, album).Scan(&track.UUID, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID)
if err != nil {
@ -137,8 +137,8 @@ func insertNewTrack(track *Track, name string, length int, mbid string, spotifyI
track.MusicBrainzID = mbid
track.SpotifyID = spotifyId
_, err := tx.Exec("INSERT INTO `tracks` (`uuid`, `name`, `length`, `mbid`, `spotify_id`) "+
"VALUES (UUID_TO_BIN(?, true),?,?,?,?)", track.UUID, track.Name, track.Length, track.MusicBrainzID, track.SpotifyID)
_, err := tx.Exec("INSERT INTO tracks (uuid, name, length, mbid, spotify_id) "+
"VALUES ($1,$2,$3,$4,$5)", track.UUID, track.Name, track.Length, track.MusicBrainzID, track.SpotifyID)
return err
}
@ -158,8 +158,8 @@ func (track *Track) linkTrack(album string, artists []string, tx *sql.Tx) error
}
func (track *Track) linkTrackToAlbum(albumUuid string, tx *sql.Tx) error {
_, err := tx.Exec("INSERT INTO `track_album` (`track`, `album`) "+
"VALUES (UUID_TO_BIN(?, true), UUID_TO_BIN(?, true))", track.UUID, albumUuid)
_, err := tx.Exec("INSERT INTO track_album (track, album) "+
"VALUES ($1, $2)", track.UUID, albumUuid)
return err
}
@ -167,8 +167,8 @@ func (track *Track) linkTrackToAlbum(albumUuid string, tx *sql.Tx) error {
func (track *Track) linkTrackToArtists(artists []string, tx *sql.Tx) error {
var err error
for _, artist := range artists {
_, err = tx.Exec("INSERT INTO `track_artist` (`track`, `artist`) "+
"VALUES (UUID_TO_BIN(?, true),UUID_TO_BIN(?, true))", track.UUID, artist)
_, err = tx.Exec("INSERT INTO track_artist (track, artist) "+
"VALUES ($1,$2)", track.UUID, artist)
if err != nil {
return err
}
@ -178,18 +178,18 @@ func (track *Track) linkTrackToArtists(artists []string, tx *sql.Tx) error {
}
func (track *Track) updateTrack(col string, val string, tx *sql.Tx) error {
_, err := tx.Exec("UPDATE `tracks` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, track.UUID)
_, err := tx.Exec("UPDATE tracks SET "+col+" = $1 WHERE uuid = $2", val, track.UUID)
return err
}
func getTrackByUUID(uuid string) (Track, error) {
var track Track
err := db.QueryRow("SELECT BIN_TO_UUID(`tracks`.`uuid`, true), `tracks`.`name`, IFNULL(`albums`.`desc`,''), IFNULL(BIN_TO_UUID(`albums`.`uuid`, true),''), `tracks`.`length`, `tracks`.`mbid`, `tracks`.`spotify_id` "+
"FROM `tracks` "+
err := db.QueryRow("SELECT tracks.uuid, tracks.name, IFNULL(albums.desc,''), IFNULL(albums.uuid,''), tracks.length, tracks.mbid, tracks.spotify_id "+
"FROM tracks "+
"LEFT JOIN track_album ON track_album.track = tracks.uuid "+
"LEFT JOIN albums ON track_album.album = albums.uuid "+
"WHERE `tracks`.`uuid` = UUID_TO_BIN(?, true)",
"WHERE tracks.uuid = $1",
uuid).Scan(&track.UUID, &track.Name, &track.Desc, &track.Img, &track.Length, &track.MusicBrainzID, &track.SpotifyID)
if err != nil {
@ -203,13 +203,13 @@ func getTrackByUUID(uuid string) (Track, error) {
func getTopTracks(userUuid string) (TopTracks, error) {
var topTracks TopTracks
rows, err := db.Query("SELECT BIN_TO_UUID(`tracks`.`uuid`, true), `tracks`.`name`, IFNULL(BIN_TO_UUID(`albums`.`uuid`, true),''), count(*) "+
"FROM `scrobbles` "+
"JOIN `tracks` ON `tracks`.`uuid` = `scrobbles`.`track` "+
rows, err := db.Query("SELECT tracks.uuid, tracks.name, IFNULL(albums.uuid,''), count(*) "+
"FROM scrobbles "+
"JOIN tracks ON tracks.uuid = scrobbles.track "+
"JOIN track_album ON track_album.track = tracks.uuid "+
"JOIN albums ON track_album.album = albums.uuid "+
"WHERE `user` = UUID_TO_BIN(?, true) "+
"GROUP BY `scrobbles`.`track` "+
"WHERE user = $1 "+
"GROUP BY scrobbles.track "+
"ORDER BY count(*) DESC "+
"LIMIT 14",
userUuid)
@ -251,9 +251,9 @@ func (track *Track) loadExtraTrackInfo() error {
func (track *Track) getArtistsForTrack() error {
artists := []Artist{}
rows, err := db.Query("SELECT BIN_TO_UUID(`track_artist`.`artist`, true) "+
"FROM `track_artist` "+
"WHERE `track_artist`.`track` = UUID_TO_BIN(?, true)",
rows, err := db.Query("SELECT track_artist.artist "+
"FROM track_artist "+
"WHERE track_artist.track = $1",
track.UUID)
if err != nil {
log.Printf("Failed to fetch artists for track: %+v", err)
@ -283,9 +283,9 @@ func (track *Track) getArtistsForTrack() error {
func (track *Track) getAlbumsForTrack() error {
albums := []Album{}
rows, err := db.Query("SELECT BIN_TO_UUID(`track_album`.`album`, true) "+
"FROM `track_album` "+
"WHERE `track_album`.`track` = UUID_TO_BIN(?, true)",
rows, err := db.Query("SELECT track_album.album "+
"FROM track_album "+
"WHERE track_album.track = $1",
track.UUID)
if err != nil {
log.Printf("Failed to fetch album for track: %+v", err)
@ -320,7 +320,7 @@ func getTopUsersForTrackUUID(trackUUID string, limit int, page int) (TopUserTrac
// Yeah this isn't great. But for now.. it works! Cache later
// TODO: This is counting total scrobbles, not unique users
total, err := getDbCount(
"SELECT COUNT(*) FROM `scrobbles` WHERE `track` = UUID_TO_BIN(?, true) GROUP BY `track`, `user`", trackUUID)
"SELECT COUNT(*) FROM scrobbles WHERE track = $1 GROUP BY track, user", trackUUID)
if err != nil {
log.Printf("Failed to fetch scrobble count: %+v", err)
@ -328,12 +328,12 @@ func getTopUsersForTrackUUID(trackUUID string, limit int, page int) (TopUserTrac
}
rows, err := db.Query(
"SELECT BIN_TO_UUID(`scrobbles`.`user`, true), `users`.`username`, COUNT(*) "+
"FROM `scrobbles` "+
"JOIN `users` ON `scrobbles`.`user` = `users`.`uuid` "+
"WHERE `track` = UUID_TO_BIN(?, true) "+
"GROUP BY `scrobbles`.`user` "+
"ORDER BY COUNT(*) DESC LIMIT ?",
"SELECT scrobbles.user, users.username, COUNT(*) "+
"FROM scrobbles "+
"JOIN users ON scrobbles.user = users.uuid "+
"WHERE track = $1 "+
"GROUP BY scrobbles.user "+
"ORDER BY COUNT(*) DESC LIMIT $2",
trackUUID, limit)
if err != nil {

View file

@ -99,7 +99,7 @@ func loginUser(logReq *RequestRequest, ip net.IP) ([]byte, error) {
}
if strings.Contains(logReq.Username, "@") {
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `username`, `email`, `password`, `admin`, `mod` FROM `users` WHERE `email` = ? AND `active` = 1",
err := db.QueryRow("SELECT uuid, username, email, password, admin, mod FROM users WHERE email = $1 AND active = true",
logReq.Username).Scan(&user.UUID, &user.Username, &user.Email, &user.Password, &user.Admin, &user.Mod)
if err != nil {
if err == sql.ErrNoRows {
@ -107,7 +107,7 @@ func loginUser(logReq *RequestRequest, ip net.IP) ([]byte, error) {
}
}
} else {
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `username`, `email`, `password`, `admin`, `mod` FROM `users` WHERE `username` = ? AND `active` = 1",
err := db.QueryRow("SELECT uuid, username, email, password, admin, mod FROM users WHERE username = $1 AND active = true",
logReq.Username).Scan(&user.UUID, &user.Username, &user.Email, &user.Password, &user.Admin, &user.Mod)
if err == sql.ErrNoRows {
return resp, errors.New("Invalid Username or Password")
@ -136,20 +136,24 @@ func loginUser(logReq *RequestRequest, ip net.IP) ([]byte, error) {
// insertUser - Does the dirtywork!
func insertUser(username string, email string, password []byte, ip net.IP) error {
token := generateToken(32)
uuid := newUUID()
log.Printf(ip.String())
_, err := db.Exec("INSERT INTO users (uuid, created_at, created_ip, modified_at, modified_ip, username, email, password, token) "+
"VALUES (UUID_TO_BIN(UUID(), true),NOW(),?,NOW(),?,?,?,?,?)", ip, ip, username, email, password, token)
"VALUES ($1,NOW(),$2,NOW(),$3,$4,$5,$6,$7)", uuid, ip.String(), ip.String(), username, email, password, token)
return err
}
func (user *User) updateUser(field string, value string, ip net.IP) error {
_, err := db.Exec("UPDATE users SET `"+field+"` = ?, modified_at = NOW(), modified_ip = ? WHERE uuid = UUID_TO_BIN(?, true)", value, ip, user.UUID)
_, err := db.Exec("UPDATE users SET "+field+" = $1, modified_at = NOW(), modified_ip = $2 WHERE uuid = $3", value, ip, user.UUID)
return err
}
func (user *User) updateUserDirect(field string, value string) error {
_, err := db.Exec("UPDATE users SET `"+field+"` = ? WHERE uuid = UUID_TO_BIN(?, true)", value, user.UUID)
_, err := db.Exec("UPDATE users SET "+field+" = $1 WHERE uuid = $2", value, user.UUID)
return err
}
@ -172,7 +176,7 @@ func isValidPassword(password string, user User) bool {
// userAlreadyExists - Returns bool indicating if a record exists for either username or email
// Using two look ups to make use of DB indexes.
func userAlreadyExists(req *RequestRequest) bool {
count, err := getDbCount("SELECT COUNT(*) FROM users WHERE username = ?", req.Username)
count, err := getDbCount("SELECT COUNT(*) FROM users WHERE username = $1", req.Username)
if err != nil {
fmt.Printf("Error querying for duplicate users: %v", err)
return true
@ -184,7 +188,7 @@ func userAlreadyExists(req *RequestRequest) bool {
if req.Email != "" {
// Only run email check if there's an email...
count, err = getDbCount("SELECT COUNT(*) FROM users WHERE email = ?", req.Email)
count, err = getDbCount("SELECT COUNT(*) FROM users WHERE email = $1", req.Email)
}
if err != nil {
@ -197,7 +201,7 @@ func userAlreadyExists(req *RequestRequest) bool {
func getUserByUUID(uuid string) (User, error) {
var user User
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `created_at`, `created_ip`, `modified_at`, `modified_ip`, `username`, `email`, `password`, `verified`, `admin`, `mod`, `timezone`, `token` FROM `users` WHERE `uuid` = UUID_TO_BIN(?, true) AND `active` = 1",
err := db.QueryRow("SELECT uuid, created_at, created_ip, modified_at, modified_ip, username, email, password, verified, admin, mod, timezone, token FROM users WHERE uuid = $1 AND active = true",
uuid).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Mod, &user.Timezone, &user.Token)
if err == sql.ErrNoRows {
@ -209,7 +213,7 @@ func getUserByUUID(uuid string) (User, error) {
func getUserByUsername(username string) (User, error) {
var user User
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `created_at`, `created_ip`, `modified_at`, `modified_ip`, `username`, `email`, `password`, `verified`, `admin`, `mod`, `timezone`, `token` FROM `users` WHERE `username` = ? AND `active` = 1",
err := db.QueryRow("SELECT uuid, created_at, created_ip, modified_at, modified_ip, username, email, password, verified, admin, mod, timezone, token FROM users WHERE username = $1 AND active = true",
username).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Mod, &user.Timezone, &user.Token)
if err == sql.ErrNoRows {
@ -221,7 +225,7 @@ func getUserByUsername(username string) (User, error) {
func getUserByEmail(email string) (User, error) {
var user User
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `created_at`, `created_ip`, `modified_at`, `modified_ip`, `username`, `email`, `password`, `verified`, `admin`, `mod`, `timezone`, `token` FROM `users` WHERE `email` = ? AND `active` = 1",
err := db.QueryRow("SELECT uuid, created_at, created_ip, modified_at, modified_ip, username, email, password, verified, admin, mod, timezone, token FROM users WHERE email = $1 AND active = true",
email).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Mod, &user.Timezone, &user.Token)
if err == sql.ErrNoRows {
@ -233,8 +237,8 @@ func getUserByEmail(email string) (User, error) {
func getUserByResetToken(token string) (User, error) {
var user User
err := db.QueryRow("SELECT BIN_TO_UUID(`users`.`uuid`, true), `created_at`, `created_ip`, `modified_at`, `modified_ip`, `username`, `email`, `password`, `verified`, `admin`, `mod`, `timezone`, `token` FROM `users` "+
"JOIN `resettoken` ON `resettoken`.`user` = `users`.`uuid` WHERE `resettoken`.`token` = ? AND `active` = 1",
err := db.QueryRow("SELECT users.uuid, created_at, created_ip, modified_at, modified_ip, username, email, password, verified, admin, mod, timezone, token FROM users "+
"JOIN resettoken ON resettoken.user = users.uuid WHERE resettoken.token = $1 AND active = true",
token).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Mod, &user.Timezone, &user.Token)
if err == sql.ErrNoRows {
@ -265,26 +269,26 @@ func (user *User) sendResetEmail(ip net.IP) error {
}
func (user *User) saveResetToken(token string, expiry time.Time) error {
_, _ = db.Exec("DELETE FROM `resettoken` WHERE `user` = UUID_TO_BIN(?, true)", user.UUID)
_, err := db.Exec("INSERT INTO `resettoken` (`user`, `token`, `expiry`) "+
"VALUES (UUID_TO_BIN(?, true),?, ?)", user.UUID, token, expiry)
_, _ = db.Exec("DELETE FROM resettoken WHERE user = $1", user.UUID)
_, err := db.Exec("INSERT INTO resettoken (user, token, expiry) "+
"VALUES ($1,$2,$3)", user.UUID, token, expiry)
return err
}
func clearOldResetTokens() {
_, _ = db.Exec("DELETE FROM `resettoken` WHERE `expiry` < NOW()")
_, _ = db.Exec("DELETE FROM resettoken WHERE expiry < NOW()")
}
func clearResetToken(token string) error {
_, err := db.Exec("DELETE FROM `resettoken` WHERE `token` = ?", token)
_, err := db.Exec("DELETE FROM resettoken WHERE token = $1", token)
return err
}
// checkResetToken - If a token exists check it
func checkResetToken(token string) (bool, error) {
count, err := getDbCount("SELECT COUNT(*) FROM `resettoken` WHERE `token` = ? ", token)
count, err := getDbCount("SELECT COUNT(*) FROM resettoken WHERE token = $1", token)
if err != nil {
return false, err
@ -299,7 +303,7 @@ func (user *User) updatePassword(newPassword string, ip net.IP) error {
return errors.New("Bad password")
}
_, err = db.Exec("UPDATE `users` SET `password` = ? WHERE `uuid` = UUID_TO_BIN(?, true)", hash, user.UUID)
_, err = db.Exec("UPDATE users SET password = $1 WHERE uuid = $2", hash, user.UUID)
if err != nil {
return errors.New("Failed to update password")
}
@ -317,8 +321,8 @@ func (user *User) getNavidromeTokens() (OauthToken, error) {
func getAllSpotifyUsers() ([]User, error) {
users := make([]User, 0)
rows, err := db.Query("SELECT BIN_TO_UUID(`users`.`uuid`, true), `created_at`, `created_ip`, `modified_at`, `modified_ip`, `users`.`username`, `email`, `password`, `verified`, `admin`, `mod`, `timezone` FROM `users` " +
"JOIN `oauth_tokens` ON `oauth_tokens`.`user` = `users`.`uuid` AND `oauth_tokens`.`service` = 'spotify' WHERE `users`.`active` = 1")
rows, err := db.Query("SELECT users.uuid, created_at, created_ip, modified_at, modified_ip, users.username, email, password, verified, admin, mod, timezone FROM users " +
"JOIN oauth_tokens ON oauth_tokens.user = users.uuid AND oauth_tokens.service = 'spotify' WHERE users.active = true")
if err != nil {
log.Printf("Failed to fetch spotify users: %+v", err)
@ -349,8 +353,8 @@ func getAllSpotifyUsers() ([]User, error) {
func getAllNavidromeUsers() ([]User, error) {
users := make([]User, 0)
rows, err := db.Query("SELECT BIN_TO_UUID(`users`.`uuid`, true), `created_at`, `created_ip`, `modified_at`, `modified_ip`, `users`.`username`, `email`, `password`, `verified`, `admin`, `mod`, `timezone` FROM `users` " +
"JOIN `oauth_tokens` ON `oauth_tokens`.`user` = `users`.`uuid` AND `oauth_tokens`.`service` = 'navidrome' WHERE `users`.`active` = 1")
rows, err := db.Query("SELECT users.uuid, created_at, created_ip, modified_at, modified_ip, users.username, email, password, verified, admin, mod, timezone FROM users " +
"JOIN oauth_tokens ON oauth_tokens.user = users.uuid AND oauth_tokens.service = 'navidrome' WHERE users.active = true")
if err != nil {
log.Printf("Failed to fetch navidrome users: %+v", err)

View file

@ -87,7 +87,7 @@ func getUserIp(r *http.Request) net.IP {
}
if host == "" {
host = "0.0.0.0"
host = "0.0.0.0/0"
}
ip = net.ParseIP(host)
@ -103,7 +103,7 @@ func Inet_Aton(ip net.IP) int64 {
// Inet6_Aton converts an IP Address (IPv4 or IPv6) net.IP object to a hexadecimal
// representaiton. This function is the equivalent of
// inet6_aton({{ ip address }}) in MySQL.
// inet6_aton({{ ip address }}) in Postgres.
func Inet6_Aton(ip net.IP) string {
ipv4 := false
if ip.To4() != nil {