diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9760bb90..cc240826 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,7 @@ stages:
- bundle
variables:
- VERSION: 0.0.32
+ VERSION: 0.0.33
build-go:
image: golang:1.16.7
diff --git a/docs/changelog.md b/docs/changelog.md
index 36e65e13..34c38fa4 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -1,3 +1,7 @@
+# 0.0.33
+- Add mod permission
+- Add track/edit page
+
# 0.0.32
- Add related records into track API
- Build out track page to show links to related records
diff --git a/internal/goscrobble/jwt.go b/internal/goscrobble/jwt.go
index 4e9d2390..94ab019c 100644
--- a/internal/goscrobble/jwt.go
+++ b/internal/goscrobble/jwt.go
@@ -34,6 +34,7 @@ func generateJWTToken(user User, existingRefresh string) (string, error) {
atClaims["username"] = user.Username
atClaims["email"] = user.Email
atClaims["admin"] = user.Admin
+ atClaims["mod"] = user.Mod
atClaims["iat"] = time.Now().Unix()
atClaims["exp"] = time.Now().Add(JwtExpiry).Unix()
atClaims["refresh_token"] = refreshToken
@@ -80,7 +81,7 @@ func verifyJWTToken(token string) (CustomClaims, error) {
return claims, err
}
-func getClaims(token *jwt.Token) CustomClaims {
- claims, _ := token.Claims.(CustomClaims)
- return claims
-}
+// func getClaims(token *jwt.Token) CustomClaims {
+// claims, _ := token.Claims.(CustomClaims)
+// return claims
+// }
diff --git a/internal/goscrobble/server.go b/internal/goscrobble/server.go
index 9a889710..d5a91dc1 100644
--- a/internal/goscrobble/server.go
+++ b/internal/goscrobble/server.go
@@ -777,7 +777,7 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) {
}
info := ServerInfo{
- Version: "0.0.32",
+ Version: "0.0.33",
RegistrationEnabled: cachedRegistrationEnabled,
}
diff --git a/internal/goscrobble/track.go b/internal/goscrobble/track.go
index 14ad1123..2e601b57 100644
--- a/internal/goscrobble/track.go
+++ b/internal/goscrobble/track.go
@@ -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 `user`", trackUUID)
+ "SELECT COUNT(*) FROM `scrobbles` WHERE `track` = UUID_TO_BIN(?, true) GROUP BY `track`, `user`", trackUUID)
if err != nil {
log.Printf("Failed to fetch scrobble count: %+v", err)
diff --git a/internal/goscrobble/user.go b/internal/goscrobble/user.go
index 5b31272f..936cbcc6 100644
--- a/internal/goscrobble/user.go
+++ b/internal/goscrobble/user.go
@@ -28,6 +28,7 @@ type User struct {
Verified bool `json:"verified"`
Active bool `json:"active"`
Admin bool `json:"admin"`
+ Mod bool `json:"mod"`
Timezone string `json:"timezone"`
Token string `json:"token"`
}
@@ -98,16 +99,16 @@ 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` FROM `users` WHERE `email` = ? AND `active` = 1",
- logReq.Username).Scan(&user.UUID, &user.Username, &user.Email, &user.Password, &user.Admin)
+ err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `username`, `email`, `password`, `admin`, `mod` FROM `users` WHERE `email` = ? AND `active` = 1",
+ logReq.Username).Scan(&user.UUID, &user.Username, &user.Email, &user.Password, &user.Admin, &user.Mod)
if err != nil {
if err == sql.ErrNoRows {
return resp, errors.New("Invalid Username or Password")
}
}
} else {
- err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `username`, `email`, `password`, `admin` FROM `users` WHERE `username` = ? AND `active` = 1",
- logReq.Username).Scan(&user.UUID, &user.Username, &user.Email, &user.Password, &user.Admin)
+ err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `username`, `email`, `password`, `admin`, `mod` FROM `users` WHERE `username` = ? AND `active` = 1",
+ 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")
}
@@ -196,8 +197,8 @@ 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`, `timezone`, `token` FROM `users` WHERE `uuid` = UUID_TO_BIN(?, true) AND `active` = 1",
- uuid).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Timezone, &user.Token)
+ 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",
+ 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 {
return user, errors.New("Invalid JWT Token")
@@ -208,8 +209,8 @@ 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`, `timezone`, `token` FROM `users` WHERE `username` = ? AND `active` = 1",
- username).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Timezone, &user.Token)
+ 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",
+ 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 {
return user, errors.New("Invalid Username")
@@ -220,8 +221,8 @@ 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`, `timezone`, `token` FROM `users` WHERE `email` = ? AND `active` = 1",
- email).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Timezone, &user.Token)
+ 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",
+ 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 {
return user, errors.New("Invalid Email")
@@ -232,9 +233,9 @@ 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`, `timezone`, `token` FROM `users` "+
+ 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",
- token).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Timezone, &user.Token)
+ 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 {
return user, errors.New("Invalid Token")
@@ -316,7 +317,7 @@ 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`, `timezone` FROM `users` " +
+ 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")
if err != nil {
@@ -328,7 +329,7 @@ func getAllSpotifyUsers() ([]User, error) {
for rows.Next() {
var user User
- err := rows.Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Timezone)
+ err := rows.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)
if err != nil {
log.Printf("Failed to fetch spotify user: %+v", err)
return users, errors.New("Failed to fetch users")
@@ -348,7 +349,7 @@ 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`, `timezone` FROM `users` " +
+ 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")
if err != nil {
@@ -360,7 +361,7 @@ func getAllNavidromeUsers() ([]User, error) {
for rows.Next() {
var user User
- err := rows.Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Timezone)
+ err := rows.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)
if err != nil {
log.Printf("Failed to fetch navidrome user: %+v", err)
return users, errors.New("Failed to fetch users")
diff --git a/migrations/13_user_mod.down.sql b/migrations/13_user_mod.down.sql
new file mode 100644
index 00000000..cb584b55
--- /dev/null
+++ b/migrations/13_user_mod.down.sql
@@ -0,0 +1 @@
+ALTER TABLE `users` DROP COLUMN `mod`;
\ No newline at end of file
diff --git a/migrations/13_user_mod.up.sql b/migrations/13_user_mod.up.sql
new file mode 100644
index 00000000..2ea56b7a
--- /dev/null
+++ b/migrations/13_user_mod.up.sql
@@ -0,0 +1 @@
+ALTER TABLE `users` ADD COLUMN `mod` TINYINT(1) NOT NULL DEFAULT 0 AFTER `admin`;
\ No newline at end of file
diff --git a/web/src/Api/index.js b/web/src/Api/index.js
index 5f2cbc7f..734462b8 100644
--- a/web/src/Api/index.js
+++ b/web/src/Api/index.js
@@ -59,6 +59,7 @@ export const PostLogin = (formValues) => {
exp: expandedUser.exp,
username: expandedUser.username,
admin: expandedUser.admin,
+ mod: expandedUser.mod,
refresh_token: expandedUser.refresh_token,
refresh_exp: expandedUser.refresh_exp,
}
@@ -92,6 +93,7 @@ export const PostRefreshToken = (refreshToken) => {
exp: expandedUser.exp,
username: expandedUser.username,
admin: expandedUser.admin,
+ mod: expandedUser.mod,
refresh_token: expandedUser.refresh_token,
refresh_exp: expandedUser.refresh_exp,
}
diff --git a/web/src/App.js b/web/src/App.js
index 520cbe07..5ca5883f 100644
--- a/web/src/App.js
+++ b/web/src/App.js
@@ -5,6 +5,7 @@ import Profile from './Pages/Profile';
import Artist from './Pages/Artist';
import Album from './Pages/Album';
import Track from './Pages/Track';
+import TrackEdit from './Pages/TrackEdit';
import User from './Pages/User';
import Admin from './Pages/Admin';
import Login from './Pages/Login';
@@ -36,6 +37,7 @@ const App = () => {