feat: 门户网站初始提交
- Go + Gin + html/template 服务端渲染 - 主页:Google 风格搜索框 + 导航卡片 - 后台:卡片 CRUD、搜索引擎配置、主页背景/标题配置 - 图片上传:支持 jpg/jpeg/png/gif,自动压缩,缩略图参数 ?thumb=1 - 安全:登录日志、修改密码、IP 自动封禁、IP 白名单 - 访问统计:主页访问/卡片点击/搜索追踪、实时流量、IP 统计 - SQLite 存储(modernc.org/sqlite,纯 Go) - 内存 Session + bcrypt 密码哈希
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"simple_portal/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CardsList renders the admin cards management page.
|
||||
func CardsList(c *gin.Context) {
|
||||
username, _ := c.Get("username")
|
||||
cards, err := models.GetAllCards()
|
||||
if err != nil {
|
||||
c.HTML(http.StatusInternalServerError, "admin/cards.html", gin.H{
|
||||
"Title": "卡片管理",
|
||||
"Username": username,
|
||||
"Error": "Failed to load cards",
|
||||
"Cards": []models.Card{},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.HTML(http.StatusOK, "admin/cards.html", gin.H{
|
||||
"Title": "卡片管理",
|
||||
"Username": username,
|
||||
"Cards": cards,
|
||||
})
|
||||
}
|
||||
|
||||
// CardCreateGet renders the form for creating a new card.
|
||||
func CardCreateGet(c *gin.Context) {
|
||||
username, _ := c.Get("username")
|
||||
c.HTML(http.StatusOK, "admin/card_form.html", gin.H{
|
||||
"Title": "新建卡片",
|
||||
"Username": username,
|
||||
"Card": nil,
|
||||
"IsEdit": false,
|
||||
})
|
||||
}
|
||||
|
||||
// CardCreatePost handles the form submission for creating a new card.
|
||||
func CardCreatePost(c *gin.Context) {
|
||||
card := &models.Card{
|
||||
Icon: c.PostForm("icon"),
|
||||
Title: c.PostForm("title"),
|
||||
Subtitle: c.PostForm("subtitle"),
|
||||
URL: c.PostForm("url"),
|
||||
Enabled: c.PostForm("enabled") == "1",
|
||||
}
|
||||
|
||||
if card.Title == "" || card.URL == "" {
|
||||
username, _ := c.Get("username")
|
||||
c.HTML(http.StatusOK, "admin/card_form.html", gin.H{
|
||||
"Title": "新建卡片",
|
||||
"Username": username,
|
||||
"Card": card,
|
||||
"IsEdit": false,
|
||||
"Error": "标题和链接不能为空",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.CreateCard(card); err != nil {
|
||||
username, _ := c.Get("username")
|
||||
c.HTML(http.StatusOK, "admin/card_form.html", gin.H{
|
||||
"Title": "新建卡片",
|
||||
"Username": username,
|
||||
"Card": card,
|
||||
"IsEdit": false,
|
||||
"Error": "创建失败: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
}
|
||||
|
||||
// CardEditGet renders the form for editing an existing card.
|
||||
func CardEditGet(c *gin.Context) {
|
||||
username, _ := c.Get("username")
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
card, err := models.GetCardByID(id)
|
||||
if err != nil || card == nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
c.HTML(http.StatusOK, "admin/card_form.html", gin.H{
|
||||
"Title": "编辑卡片",
|
||||
"Username": username,
|
||||
"Card": card,
|
||||
"IsEdit": true,
|
||||
})
|
||||
}
|
||||
|
||||
// CardEditPost handles the form submission for updating an existing card.
|
||||
func CardEditPost(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
card, err := models.GetCardByID(id)
|
||||
if err != nil || card == nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
card.Icon = c.PostForm("icon")
|
||||
card.Title = c.PostForm("title")
|
||||
card.Subtitle = c.PostForm("subtitle")
|
||||
card.URL = c.PostForm("url")
|
||||
card.Enabled = c.PostForm("enabled") == "1"
|
||||
|
||||
if card.Title == "" || card.URL == "" {
|
||||
username, _ := c.Get("username")
|
||||
c.HTML(http.StatusOK, "admin/card_form.html", gin.H{
|
||||
"Title": "编辑卡片",
|
||||
"Username": username,
|
||||
"Card": card,
|
||||
"IsEdit": true,
|
||||
"Error": "标题和链接不能为空",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.UpdateCard(card); err != nil {
|
||||
username, _ := c.Get("username")
|
||||
c.HTML(http.StatusOK, "admin/card_form.html", gin.H{
|
||||
"Title": "编辑卡片",
|
||||
"Username": username,
|
||||
"Card": card,
|
||||
"IsEdit": true,
|
||||
"Error": "更新失败: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
}
|
||||
|
||||
// CardDelete handles deleting a card.
|
||||
func CardDelete(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
_ = models.DeleteCard(id)
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
}
|
||||
|
||||
// CardToggle handles toggling a card's enabled status.
|
||||
func CardToggle(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
_ = models.ToggleCard(id)
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
}
|
||||
|
||||
// CardMoveUp handles moving a card up in sort order.
|
||||
func CardMoveUp(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
_ = models.MoveCardUp(id)
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
}
|
||||
|
||||
// CardMoveDown handles moving a card down in sort order.
|
||||
func CardMoveDown(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
return
|
||||
}
|
||||
|
||||
_ = models.MoveCardDown(id)
|
||||
c.Redirect(http.StatusFound, "/admin/cards")
|
||||
}
|
||||
Reference in New Issue
Block a user