mirror of
https://github.com/idanoo/GoScrobble
synced 2025-07-01 21:52:19 +00:00
Scrobbles work!
This commit is contained in:
parent
74d1fec817
commit
16531f9fa1
27 changed files with 568 additions and 61 deletions
85
internal/goscrobble/album.go
Normal file
85
internal/goscrobble/album.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
package goscrobble
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Album struct {
|
||||
Uuid string `json:"uuid"`
|
||||
Name string `json:"name"`
|
||||
Desc sql.NullString `json:"desc"`
|
||||
Img sql.NullString `json:"img"`
|
||||
MusicBrainzID sql.NullString `json:"mbid"`
|
||||
}
|
||||
|
||||
// insertAlbum - This will return if it exists or create it based on MBID > Name
|
||||
func insertAlbum(name string, mbid string, artists []string, tx *sql.Tx) (Album, error) {
|
||||
album := Album{}
|
||||
|
||||
if mbid != "" {
|
||||
album = fetchAlbum("mbid", mbid, tx)
|
||||
if album.Uuid == "" {
|
||||
err := insertNewAlbum(name, mbid, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting album via MBID %s %+v", name, err)
|
||||
return album, errors.New("Failed to insert album")
|
||||
}
|
||||
|
||||
album = fetchAlbum("mbid", mbid, tx)
|
||||
}
|
||||
} else {
|
||||
album = fetchAlbum("name", name, tx)
|
||||
if album.Uuid == "" {
|
||||
err := insertNewAlbum(name, mbid, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting album via Name %s %+v", name, err)
|
||||
return album, errors.New("Failed to insert album")
|
||||
}
|
||||
|
||||
album = fetchAlbum("name", name, tx)
|
||||
}
|
||||
}
|
||||
|
||||
if album.Uuid == "" {
|
||||
return album, errors.New("Unable to fetch album!")
|
||||
}
|
||||
|
||||
return album, nil
|
||||
}
|
||||
|
||||
func fetchAlbum(col string, val string, tx *sql.Tx) Album {
|
||||
var album Album
|
||||
err := tx.QueryRow(
|
||||
"SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `albums` WHERE `"+col+"` = ?",
|
||||
val).Scan(&album.Uuid, &album.Name, &album.Desc, &album.Img, &album.MusicBrainzID)
|
||||
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
log.Printf("Error fetching albums: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return album
|
||||
}
|
||||
|
||||
func insertNewAlbum(name string, mbid string, tx *sql.Tx) error {
|
||||
_, err := tx.Exec("INSERT INTO `albums` (`uuid`, `name`, `mbid`) "+
|
||||
"VALUES (UUID_TO_BIN(UUID(), true),?,?)", name, mbid)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (album *Album) linkAlbumToArtists(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)", album.Uuid, artist)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
72
internal/goscrobble/artist.go
Normal file
72
internal/goscrobble/artist.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package goscrobble
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Artist struct {
|
||||
Uuid string `json:"uuid"`
|
||||
Name string `json:"name"`
|
||||
Desc sql.NullString `json:"desc"`
|
||||
Img sql.NullString `json:"img"`
|
||||
MusicBrainzID sql.NullString `json:"mbid"`
|
||||
}
|
||||
|
||||
// insertArtist - This will return if it exists or create it based on MBID > Name
|
||||
func insertArtist(name string, mbid string, tx *sql.Tx) (Artist, error) {
|
||||
artist := Artist{}
|
||||
|
||||
if mbid != "" {
|
||||
artist = fetchArtist("mbid", mbid, tx)
|
||||
if artist.Uuid == "" {
|
||||
err := insertNewArtist(name, mbid, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting artist via MBID %s %+v", name, err)
|
||||
return artist, errors.New("Failed to insert artist")
|
||||
}
|
||||
|
||||
artist = fetchArtist("mbid", mbid, tx)
|
||||
}
|
||||
} else {
|
||||
artist = fetchArtist("name", name, tx)
|
||||
if artist.Uuid == "" {
|
||||
err := insertNewArtist(name, mbid, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting artist via Name %s %+v", name, err)
|
||||
return artist, errors.New("Failed to insert artist")
|
||||
}
|
||||
|
||||
artist = fetchArtist("name", name, tx)
|
||||
}
|
||||
}
|
||||
|
||||
if artist.Uuid == "" {
|
||||
return artist, errors.New("Unable to fetch artist!")
|
||||
}
|
||||
|
||||
return artist, nil
|
||||
}
|
||||
|
||||
func fetchArtist(col string, val string, tx *sql.Tx) Artist {
|
||||
var artist Artist
|
||||
err := tx.QueryRow(
|
||||
"SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `artists` WHERE `"+col+"` = ?",
|
||||
val).Scan(&artist.Uuid, &artist.Name, &artist.Desc, &artist.Img, &artist.MusicBrainzID)
|
||||
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
log.Printf("Error fetching artists: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return artist
|
||||
}
|
||||
|
||||
func insertNewArtist(name string, mbid string, tx *sql.Tx) error {
|
||||
_, err := tx.Exec("INSERT INTO `artists` (`uuid`, `name`, `mbid`) "+
|
||||
"VALUES (UUID_TO_BIN(UUID(), true),?,?)", name, mbid)
|
||||
|
||||
return err
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
|
@ -22,8 +23,13 @@ func InitDb() {
|
|||
dbUser := os.Getenv("MYSQL_USER")
|
||||
dbPass := os.Getenv("MYSQL_PASS")
|
||||
dbName := os.Getenv("MYSQL_DB")
|
||||
timeZone := os.Getenv("TIMEZONE")
|
||||
dbTz := ""
|
||||
if timeZone != "" {
|
||||
dbTz = "&loc=" + strings.Replace(timeZone, "/", fmt.Sprintf("%%2F"), 1)
|
||||
}
|
||||
|
||||
dbConn, err := sql.Open("mysql", dbUser+":"+dbPass+"@tcp("+dbHost+")/"+dbName+"?multiStatements=true")
|
||||
dbConn, err := sql.Open("mysql", dbUser+":"+dbPass+"@tcp("+dbHost+")/"+dbName+"?multiStatements=true"+dbTz)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,50 @@
|
|||
package goscrobble
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
// ParseJellyfinInput - Transform API data into a common struct
|
||||
func ParseJellyfinInput(test string) string {
|
||||
return test
|
||||
func ParseJellyfinInput(userUUID string, data map[string]interface{}, ip net.IP, tx *sql.Tx) error {
|
||||
log.Printf("%+v : %+v", userUUID, data)
|
||||
|
||||
// Insert artist if not exist
|
||||
artist, err := insertArtist(fmt.Sprintf("%s", data["Artist"]), fmt.Sprintf("%s", data["Provider_musicbrainzartist"]), tx)
|
||||
if err != nil {
|
||||
log.Printf("%+v", err)
|
||||
return errors.New("Failed to map artist")
|
||||
}
|
||||
|
||||
// Insert album if not exist
|
||||
artists := []string{artist.Uuid}
|
||||
album, err := insertAlbum(fmt.Sprintf("%s", data["Album"]), fmt.Sprintf("%s", data["Provider_musicbrainzalbum"]), artists, tx)
|
||||
if err != nil {
|
||||
log.Printf("%+v", err)
|
||||
return errors.New("Failed to map album")
|
||||
}
|
||||
|
||||
// Insert album if not exist
|
||||
track, err := insertTrack(fmt.Sprintf("%s", data["Name"]), fmt.Sprintf("%s", data["Provider_musicbrainztrack"]), album.Uuid, artists, tx)
|
||||
if err != nil {
|
||||
log.Printf("%+v", err)
|
||||
return errors.New("Failed to map track")
|
||||
}
|
||||
|
||||
// Insert album if not exist
|
||||
err = insertScrobble(userUUID, track.Uuid, ip, tx)
|
||||
if err != nil {
|
||||
log.Printf("%+v", err)
|
||||
return errors.New("Failed to map track")
|
||||
}
|
||||
|
||||
_ = album
|
||||
_ = artist
|
||||
_ = track
|
||||
|
||||
// Insert track if not exist
|
||||
return nil
|
||||
}
|
||||
|
|
50
internal/goscrobble/scrobble.go
Normal file
50
internal/goscrobble/scrobble.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package goscrobble
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Scrobble struct {
|
||||
Uuid string `json:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
CreatedIp net.IP `json:"created_ip"`
|
||||
User string `json:"user"`
|
||||
Track string `json:"track"`
|
||||
}
|
||||
|
||||
// insertScrobble - This will return if it exists or create it based on MBID > Name
|
||||
func insertScrobble(user string, track string, ip net.IP, tx *sql.Tx) error {
|
||||
err := insertNewScrobble(user, track, ip, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting scrobble %s %+v", user, err)
|
||||
return errors.New("Failed to insert scrobble!")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchScrobble(col string, val string, tx *sql.Tx) Scrobble {
|
||||
var scrobble Scrobble
|
||||
err := tx.QueryRow(
|
||||
"SELECT BIN_TO_UUID(`uuid`, true), `created_at`, `created_ip`, `user`, `track` FROM `scrobbles` WHERE `"+col+"` = ?",
|
||||
val).Scan(&scrobble.Uuid, &scrobble.CreatedAt, &scrobble.CreatedIp, &scrobble.User, &scrobble.Track)
|
||||
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
log.Printf("Error fetching scrobbles: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return scrobble
|
||||
}
|
||||
|
||||
func insertNewScrobble(user string, track string, ip net.IP, tx *sql.Tx) error {
|
||||
_, err := tx.Exec("INSERT INTO `scrobbles` (`uuid`, `created_at`, `created_ip`, `user`, `track`) "+
|
||||
"VALUES (UUID_TO_BIN(UUID(), true), NOW(), ?, UUID_TO_BIN(?, true),UUID_TO_BIN(?, true))", ip, user, track)
|
||||
|
||||
return err
|
||||
}
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/cors"
|
||||
|
@ -25,10 +26,10 @@ type jsonResponse struct {
|
|||
}
|
||||
|
||||
// Limits to 1 req / 10 sec
|
||||
var heavyLimiter = NewIPRateLimiter(0.1, 1)
|
||||
var heavyLimiter = NewIPRateLimiter(0.25, 2)
|
||||
|
||||
// Limits to 5 req / sec
|
||||
var standardLimiter = NewIPRateLimiter(5, 5)
|
||||
var standardLimiter = NewIPRateLimiter(1, 5)
|
||||
|
||||
// List of Reverse proxies
|
||||
var ReverseProxies []string
|
||||
|
@ -45,15 +46,16 @@ func HandleRequests(port string) {
|
|||
v1 := r.PathPrefix("/api/v1").Subrouter()
|
||||
|
||||
// Static Token for /ingress
|
||||
v1.HandleFunc("/ingress/jellyfin", tokenMiddleware(serveEndpoint))
|
||||
v1.HandleFunc("/ingress/jellyfin", tokenMiddleware(handleIngress))
|
||||
|
||||
// JWT Auth
|
||||
v1.HandleFunc("/profile/{id}", jwtMiddleware(serveEndpoint))
|
||||
// v1.HandleFunc("/profile/{id}", jwtMiddleware(handleIngress))
|
||||
|
||||
// No Auth
|
||||
v1.HandleFunc("/register", limitMiddleware(handleRegister, heavyLimiter)).Methods("POST")
|
||||
v1.HandleFunc("/login", limitMiddleware(handleLogin, standardLimiter)).Methods("POST")
|
||||
v1.HandleFunc("/logout", serveEndpoint).Methods("POST")
|
||||
// For now just trash JWT in frontend until we have full state management "Good enough"
|
||||
// v1.HandleFunc("/logout", handleIngress).Methods("POST")
|
||||
|
||||
// This just prevents it serving frontend stuff over /api
|
||||
r.PathPrefix("/api")
|
||||
|
@ -126,9 +128,21 @@ func generateJsonError(m string) []byte {
|
|||
// tokenMiddleware - Validates token to a user
|
||||
func tokenMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
throwUnauthorized(w, "Invalid API Token")
|
||||
return
|
||||
// next(res, req)
|
||||
fullToken := r.Header.Get("Authorization")
|
||||
authToken := strings.Replace(fullToken, "Bearer ", "", 1)
|
||||
if authToken == "" {
|
||||
throwUnauthorized(w, "A token is required")
|
||||
}
|
||||
|
||||
userUuid, err := getUserForToken(authToken)
|
||||
if err != nil {
|
||||
throwUnauthorized(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Lets tack this on the request for now..
|
||||
r.Header.Set("UserUUID", userUuid)
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,8 +150,7 @@ func tokenMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
|||
func jwtMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
throwUnauthorized(w, "Invalid JWT Token")
|
||||
return
|
||||
// next(res, req)
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +188,7 @@ func handleRegister(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
msg := generateJsonMessage("User created succesfully")
|
||||
msg := generateJsonMessage("User created succesfully. You may now login")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write(msg)
|
||||
}
|
||||
|
@ -202,14 +215,35 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// serveEndpoint - API stuffs
|
||||
func serveEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := decodeJson(r.Body)
|
||||
func handleIngress(w http.ResponseWriter, r *http.Request) {
|
||||
bodyJson, err := decodeJson(r.Body)
|
||||
if err != nil {
|
||||
// If we can't decode. Lets tell them nicely.
|
||||
http.Error(w, "{\"error\":\"Invalid JSON\"}", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
ingressType := strings.Replace(r.URL.Path, "/api/v1/ingress/", "", 1)
|
||||
log.Println(ingressType)
|
||||
switch ingressType {
|
||||
case "jellyfin":
|
||||
tx, _ := db.Begin()
|
||||
ip := getUserIp(r)
|
||||
err := ParseJellyfinInput(r.Header.Get("UserUUID"), bodyJson, ip, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting track: %+v", err)
|
||||
tx.Rollback()
|
||||
throwBadReq(w, err.Error())
|
||||
return
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
throwBadReq(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
throwOkMessage(w, "{}")
|
||||
return
|
||||
}
|
||||
// Lets trick 'em for now ;) ;)
|
||||
fmt.Fprintf(w, "{}")
|
||||
}
|
||||
|
|
25
internal/goscrobble/tokens.go
Normal file
25
internal/goscrobble/tokens.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package goscrobble
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
func generateToken(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func getUserForToken(token string) (string, error) {
|
||||
var uuid string
|
||||
err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true) FROM `users` WHERE `token` = ? AND `active` = 1", token).Scan(&uuid)
|
||||
if err != nil {
|
||||
return "", errors.New("Invalid Token")
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
112
internal/goscrobble/track.go
Normal file
112
internal/goscrobble/track.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
package goscrobble
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Track struct {
|
||||
Uuid string `json:"uuid"`
|
||||
Name string `json:"name"`
|
||||
Desc sql.NullString `json:"desc"`
|
||||
Img sql.NullString `json:"img"`
|
||||
MusicBrainzID sql.NullString `json:"mbid"`
|
||||
}
|
||||
|
||||
// insertTrack - This will return if it exists or create it based on MBID > Name
|
||||
func insertTrack(name string, mbid string, album string, artists []string, tx *sql.Tx) (Track, error) {
|
||||
track := Track{}
|
||||
|
||||
if mbid != "" {
|
||||
track = fetchTrack("mbid", mbid, tx)
|
||||
if track.Uuid == "" {
|
||||
err := insertNewTrack(name, mbid, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting track via MBID %s %+v", name, err)
|
||||
return track, errors.New("Failed to insert track")
|
||||
}
|
||||
|
||||
track = fetchTrack("mbid", mbid, tx)
|
||||
err = track.linkTrack(album, artists, tx)
|
||||
if err != nil {
|
||||
return track, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
track = fetchTrack("name", name, tx)
|
||||
if track.Uuid == "" {
|
||||
err := insertNewTrack(name, mbid, tx)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting track via Name %s %+v", name, err)
|
||||
return track, errors.New("Failed to insert track")
|
||||
}
|
||||
|
||||
track = fetchTrack("name", name, tx)
|
||||
err = track.linkTrack(album, artists, tx)
|
||||
if err != nil {
|
||||
return track, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if track.Uuid == "" {
|
||||
return track, errors.New("Unable to fetch track!")
|
||||
}
|
||||
|
||||
return track, nil
|
||||
}
|
||||
|
||||
func fetchTrack(col string, val string, tx *sql.Tx) Track {
|
||||
var track Track
|
||||
err := tx.QueryRow(
|
||||
"SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `tracks` WHERE `"+col+"` = ?",
|
||||
val).Scan(&track.Uuid, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID)
|
||||
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
log.Printf("Error fetching tracks: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return track
|
||||
}
|
||||
|
||||
func insertNewTrack(name string, mbid string, tx *sql.Tx) error {
|
||||
_, err := tx.Exec("INSERT INTO `tracks` (`uuid`, `name`, `mbid`) "+
|
||||
"VALUES (UUID_TO_BIN(UUID(), true),?,?)", name, mbid)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (track *Track) linkTrack(album string, artists []string, tx *sql.Tx) error {
|
||||
err := track.linkTrackToAlbum(album, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = track.linkTrackToArtists(artists, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -153,13 +153,14 @@ func generateJwt(user User) (string, error) {
|
|||
|
||||
// insertUser - Does the dirtywork!
|
||||
func insertUser(username string, email string, password []byte, ip net.IP) error {
|
||||
_, err := db.Exec("INSERT INTO users (uuid, created_at, created_ip, modified_at, modified_ip, username, email, password) "+
|
||||
"VALUES (UUID_TO_BIN(UUID(), true),NOW(),?,NOW(),?,?,?,?)", ip, ip, username, email, password)
|
||||
token := generateToken(32)
|
||||
_, 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)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func updateUser(uuid string, field string, value string, ip string) error {
|
||||
func updateUser(uuid string, field string, value string, ip net.IP) error {
|
||||
_, err := db.Exec("UPDATE users SET ? = ?, modified_at = NOW(), modified_ip = ? WHERE uuid = ?", field, value, uuid, ip)
|
||||
|
||||
return err
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -44,11 +45,14 @@ func getUserIp(r *http.Request) net.IP {
|
|||
var ip net.IP
|
||||
host, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||
if contains(ReverseProxies, host) {
|
||||
host = r.Header.Get("X-FOWARDED-FOR")
|
||||
forwardedFor := r.Header.Get("X-FOWARDED-FOR")
|
||||
if forwardedFor != "" {
|
||||
host = forwardedFor
|
||||
}
|
||||
}
|
||||
|
||||
ip = net.ParseIP(host)
|
||||
|
||||
log.Printf("%+v", ip)
|
||||
return ip
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue