feat: initial blog engine with multi-language, profile, and role system
- Gin + GORM + Tailwind CSS blog engine - OS-aware config (Linux /etc/blog_go/, Windows ./win/etc/blog_go/) - SQLite by default, MySQL support via config - Auto-migrate database + seed admin user on first run - Session-based auth (login/logout) - i18n: Chinese/English with auto-detect + manual switch - Avatar dropdown nav with click-to-toggle menu - Profile page: avatar upload, edit info, change password - Role system: admin (full access) and author (profile only) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"go_blog/i18n"
|
||||
"go_blog/models"
|
||||
)
|
||||
|
||||
// AuthRequired is middleware that protects routes. If the user is not logged in,
|
||||
// they are redirected to /login.
|
||||
func AuthRequired() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
userID := session.Get("user_id")
|
||||
if userID == nil {
|
||||
c.Redirect(http.StatusFound, "/login")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// SetUserContext is global middleware that reads the session and sets
|
||||
// template-friendly context values for all pages (language, auth state, etc.).
|
||||
func SetUserContext(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
|
||||
// --- Language detection ---
|
||||
// Priority: query param > session > Accept-Language header > default EN
|
||||
var lang i18n.Lang
|
||||
queryLang := c.Query("lang")
|
||||
|
||||
switch queryLang {
|
||||
case "zh":
|
||||
lang = i18n.ZH
|
||||
case "en":
|
||||
lang = i18n.EN
|
||||
case "":
|
||||
// Try session
|
||||
if saved, ok := session.Get("lang").(string); ok {
|
||||
lang = i18n.Lang(saved)
|
||||
}
|
||||
if lang == "" {
|
||||
// Try Accept-Language header
|
||||
lang = i18n.DetectLang(c.GetHeader("Accept-Language"))
|
||||
}
|
||||
default:
|
||||
// Unsupported language in query — fall back to English.
|
||||
lang = i18n.EN
|
||||
}
|
||||
|
||||
// Persist language in session.
|
||||
session.Set("lang", string(lang))
|
||||
session.Save()
|
||||
|
||||
// Make translations available in the Gin context.
|
||||
c.Set("tr", i18n.T(lang))
|
||||
c.Set("lang", string(lang))
|
||||
|
||||
// Set the opposite language code for the language switcher link.
|
||||
switchLang := "zh"
|
||||
if lang == i18n.ZH {
|
||||
switchLang = "en"
|
||||
}
|
||||
c.Set("switch_lang", switchLang)
|
||||
|
||||
// --- Auth state ---
|
||||
userID := session.Get("user_id")
|
||||
isLoggedIn := false
|
||||
var username string
|
||||
var avatar string
|
||||
var displayName string
|
||||
var role string
|
||||
|
||||
if userID != nil {
|
||||
isLoggedIn = true
|
||||
var user models.User
|
||||
if err := db.First(&user, userID).Error; err == nil {
|
||||
username = user.Username
|
||||
avatar = user.Avatar
|
||||
displayName = user.DisplayName
|
||||
role = user.Role
|
||||
}
|
||||
}
|
||||
|
||||
c.Set("is_logged_in", isLoggedIn)
|
||||
c.Set("username", username)
|
||||
c.Set("avatar", avatar)
|
||||
c.Set("display_name", displayName)
|
||||
c.Set("role", role)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user