Full refactor of codebase
This commit is contained in:
76
src/repository/crud.go
Normal file
76
src/repository/crud.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/ascyii/qrank/src/utils"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func FindUser(ref any) *User {
|
||||
// Session case
|
||||
if c, ok := ref.(*gin.Context); ok {
|
||||
session := sessions.Default(c)
|
||||
if uid := session.Get("user_id"); uid != nil {
|
||||
var u User
|
||||
if err := db.First(&u, uid.(uint)).Error; err == nil {
|
||||
return &u
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// String handle case
|
||||
if h, ok := ref.(string); ok {
|
||||
h = strings.TrimSpace(h)
|
||||
if h == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var u User
|
||||
var err error
|
||||
if strings.Contains(h, "@") {
|
||||
err = db.Where("LOWER(email) = ?", strings.ToLower(h)).First(&u).Error
|
||||
} else {
|
||||
err = db.Where("username = ?", h).First(&u).Error
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return &u
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func FindOrCreateUserFromEmail(email string) *User {
|
||||
var u User
|
||||
// Try to find existing user
|
||||
err := db.Where("email = ?", email).First(&u).Error // TODO: This makes bad logs
|
||||
if err == nil {
|
||||
return &u
|
||||
}
|
||||
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Println("Find user:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a new user
|
||||
u = User{
|
||||
Email: email,
|
||||
Username: utils.DefaultUsername(),
|
||||
}
|
||||
if err := EnsureUniqueUsernameAndSlug(&u); err != nil {
|
||||
log.Println("Ensure unique:", err)
|
||||
}
|
||||
if err := db.Create(&u).Error; err != nil {
|
||||
log.Println("Create user:", err)
|
||||
return nil
|
||||
}
|
||||
return &u
|
||||
}
|
||||
32
src/repository/database.go
Normal file
32
src/repository/database.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
// Open connection to sqlite
|
||||
db, err = gorm.Open(sqlite.Open("qrank.db"), &gorm.Config{})
|
||||
if err != nil {
|
||||
log.Fatal("Sqlite connect:", err)
|
||||
}
|
||||
|
||||
// Migrate the database with gorm
|
||||
if err := db.AutoMigrate(&User{}, &LoginToken{}, &Table{}, &Game{}, &GameUser{}); err != nil {
|
||||
log.Fatal("Migrate:", err)
|
||||
}
|
||||
if err := db.SetupJoinTable(&User{}, "Games", &GameUser{}); err != nil {
|
||||
log.Fatal("Setup jointable:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetDB() *gorm.DB {
|
||||
return db
|
||||
}
|
||||
32
src/repository/lookup.go
Normal file
32
src/repository/lookup.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/ascyii/qrank/src/utils"
|
||||
)
|
||||
|
||||
func EnsureUniqueUsernameAndSlug(u *User) error {
|
||||
baseU := u.Username
|
||||
baseS := utils.Slugify(u.Username)
|
||||
for i := range 5 {
|
||||
candU := baseU
|
||||
candS := baseS
|
||||
if i > 0 {
|
||||
suffix := "-" + utils.MustRandToken(1)
|
||||
candU = baseU + suffix
|
||||
candS = baseS + suffix
|
||||
}
|
||||
var cnt int64
|
||||
db.Model(&User{}).Where("username = ?", candU).Count(&cnt)
|
||||
if cnt == 0 {
|
||||
db.Model(&User{}).Where("slug = ?", candS).Count(&cnt)
|
||||
if cnt == 0 {
|
||||
u.Username = candU
|
||||
u.Slug = candS
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("cannot create unique username/slug")
|
||||
}
|
||||
67
src/repository/models.go
Normal file
67
src/repository/models.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// One knows that the user is active when there exists a session for the user
|
||||
type User struct {
|
||||
gorm.Model
|
||||
|
||||
Email string
|
||||
Username string
|
||||
Slug string
|
||||
|
||||
Elo float64
|
||||
GameCount int
|
||||
WinCount int
|
||||
LossCount int
|
||||
|
||||
Games []Game `gorm:"many2many:game_user"`
|
||||
LastLogin time.Time
|
||||
Active bool
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
gorm.Model
|
||||
|
||||
Name string
|
||||
Slug string
|
||||
GameCount int
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
gorm.Model
|
||||
|
||||
TableID *uint
|
||||
Table *Table
|
||||
|
||||
Users []User `gorm:"many2many:game_user"`
|
||||
|
||||
ScoreA int
|
||||
ScoreB int
|
||||
}
|
||||
|
||||
// Join table between game and user with extra fields
|
||||
type GameUser struct {
|
||||
gorm.Model
|
||||
|
||||
GameID uint
|
||||
Game Game
|
||||
|
||||
UserID uint
|
||||
User User
|
||||
|
||||
Side string `gorm:"size:1"`
|
||||
DeltaElo float64
|
||||
}
|
||||
|
||||
type LoginToken struct {
|
||||
gorm.Model
|
||||
|
||||
Token string
|
||||
Email string
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
42
src/repository/session.go
Normal file
42
src/repository/session.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/cookie"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var store cookie.Store
|
||||
|
||||
func init() {
|
||||
store = cookie.NewStore([]byte("secret"))
|
||||
}
|
||||
|
||||
func SetupStore(r *gin.Engine) {
|
||||
r.Use(sessions.Sessions("mysession", store))
|
||||
}
|
||||
|
||||
// SaveForm stores submitted POST form data into the session
|
||||
func SaveForm(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
form := map[string]string{}
|
||||
for key, values := range c.Request.PostForm {
|
||||
if len(values) > 0 {
|
||||
form[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
if b, err := json.Marshal(form); err == nil {
|
||||
session.Set("form_data", string(b))
|
||||
session.Save()
|
||||
}
|
||||
}
|
||||
|
||||
// SaveForm stores submitted POST form data into the session
|
||||
func SetMessage(c *gin.Context, message string) {
|
||||
session := sessions.Default(c)
|
||||
session.Set("message", message)
|
||||
session.Save()
|
||||
}
|
||||
Reference in New Issue
Block a user