初始化
This commit is contained in:
54
server/handlers/auth.go
Normal file
54
server/handlers/auth.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/middleware"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// AdminLogin 管理员登录
|
||||
func AdminLogin(c *gin.Context) {
|
||||
var req models.LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户
|
||||
user, err := repositories.GetUserByUsername(req.Username)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user"})
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)); err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid username or password"})
|
||||
return
|
||||
}
|
||||
|
||||
// 生成JWT令牌
|
||||
token, expire, err := middleware.GenerateToken(user.ID, user.Username, user.Role)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response := models.LoginResponse{
|
||||
Token: token,
|
||||
User: *repositories.BuildUserResponse(user),
|
||||
Expire: expire,
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
46
server/handlers/dashboard.go
Normal file
46
server/handlers/dashboard.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
// 仪表盘数据处理函数
|
||||
func AdminGetDashboardStats(c *gin.Context) {
|
||||
// 获取统计数据
|
||||
userCount, err := repositories.GetUserCount()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user count"})
|
||||
return
|
||||
}
|
||||
|
||||
postCount, err := repositories.GetPostCount()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get post count"})
|
||||
return
|
||||
}
|
||||
|
||||
workCount, err := repositories.GetWorkCount()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get work count"})
|
||||
return
|
||||
}
|
||||
|
||||
snippetCount, err := repositories.GetSnippetCount()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get snippet count"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
stats := gin.H{
|
||||
"users": userCount,
|
||||
"posts": postCount,
|
||||
"works": workCount,
|
||||
"snippets": snippetCount,
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, stats)
|
||||
}
|
||||
81
server/handlers/log.go
Normal file
81
server/handlers/log.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
func AdminGetRecentActivities(c *gin.Context) {
|
||||
// 获取最近10条操作日志
|
||||
logs, _, err := repositories.GetOperationLogs(1, 10)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get recent activities"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
var activities []gin.H
|
||||
for _, log := range logs {
|
||||
// 根据HTTP方法设置图标
|
||||
var icon string
|
||||
switch log.Method {
|
||||
case "POST":
|
||||
icon = "➕"
|
||||
case "PUT", "PATCH":
|
||||
icon = "✏️"
|
||||
case "DELETE":
|
||||
icon = "🗑️"
|
||||
case "GET":
|
||||
icon = "📋"
|
||||
case "OPTIONS":
|
||||
icon = "⚙️"
|
||||
default:
|
||||
icon = "📋"
|
||||
}
|
||||
|
||||
// 构建活动文本描述
|
||||
text := fmt.Sprintf("%s %s", log.Method, log.Path)
|
||||
|
||||
activities = append(activities, gin.H{
|
||||
"id": log.ID,
|
||||
"icon": icon,
|
||||
"text": text,
|
||||
"time": log.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, activities)
|
||||
}
|
||||
|
||||
// 获取操作日志列表
|
||||
func AdminGetOperationLogs(c *gin.Context) {
|
||||
// 获取分页参数
|
||||
page := 1
|
||||
pageSize := 10
|
||||
|
||||
// 从查询参数中获取分页信息
|
||||
if c.Query("page") != "" {
|
||||
c.ShouldBindQuery(&page)
|
||||
}
|
||||
|
||||
if c.Query("pageSize") != "" {
|
||||
c.ShouldBindQuery(&pageSize)
|
||||
}
|
||||
|
||||
// 获取操作日志
|
||||
logs, total, err := repositories.GetOperationLogs(page, pageSize)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get operation logs"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"list": repositories.BuildOperationLogsResponse(logs),
|
||||
"total": total,
|
||||
"page": page,
|
||||
"size": pageSize,
|
||||
})
|
||||
}
|
||||
182
server/handlers/post.go
Normal file
182
server/handlers/post.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
// 获取博客文章列表
|
||||
func GetPosts(c *gin.Context) {
|
||||
// 从数据库获取所有博客文章
|
||||
posts, err := repositories.GetPosts()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch posts"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
responses := repositories.BuildPostsResponse(posts)
|
||||
|
||||
c.JSON(http.StatusOK, responses)
|
||||
}
|
||||
|
||||
func GetPost(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
// 从数据库获取博客文章
|
||||
post, err := repositories.GetPostByID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch post"})
|
||||
return
|
||||
}
|
||||
|
||||
if post == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Post not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应,包含内容
|
||||
response := repositories.BuildPostResponse(post, true)
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
func GetPostsByTagID(c *gin.Context) {
|
||||
// 解析标签ID
|
||||
idStr := c.Param("id")
|
||||
var id uint
|
||||
_, err := fmt.Sscanf(idStr, "%d", &id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tag ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 从数据库获取标签相关的文章
|
||||
posts, err := repositories.GetPostsByTagID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch posts by tag"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
responses := repositories.BuildPostsResponse(posts)
|
||||
|
||||
c.JSON(http.StatusOK, responses)
|
||||
}
|
||||
|
||||
// 获取所有文章(包括未发布的)
|
||||
func AdminGetPosts(c *gin.Context) {
|
||||
posts, err := repositories.GetAllPosts()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get posts"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildPostsResponse(posts))
|
||||
}
|
||||
|
||||
// 创建文章
|
||||
func AdminCreatePost(c *gin.Context) {
|
||||
var post models.Post
|
||||
if err := c.ShouldBindJSON(&post); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 创建文章
|
||||
if err := repositories.CreatePost(&post); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create post"})
|
||||
return
|
||||
}
|
||||
|
||||
// 保存历史记录
|
||||
userID, _ := c.Get("userID")
|
||||
if err := repositories.SavePostHistory(&post, userID.(uint)); err != nil {
|
||||
log.Printf("Error saving post history: %v", err)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Post created successfully"})
|
||||
}
|
||||
|
||||
// 更新文章
|
||||
func AdminUpdatePost(c *gin.Context) {
|
||||
postID := c.Param("id")
|
||||
var post models.Post
|
||||
if err := c.ShouldBindJSON(&post); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置文章ID
|
||||
post.ID = postID
|
||||
|
||||
// 更新文章
|
||||
if err := repositories.UpdatePost(&post); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update post"})
|
||||
return
|
||||
}
|
||||
|
||||
// 保存历史记录
|
||||
userID, _ := c.Get("userID")
|
||||
if err := repositories.SavePostHistory(&post, userID.(uint)); err != nil {
|
||||
log.Printf("Error saving post history: %v", err)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Post updated successfully"})
|
||||
}
|
||||
|
||||
// 删除文章
|
||||
func AdminDeletePost(c *gin.Context) {
|
||||
postID := c.Param("id")
|
||||
|
||||
// 删除文章
|
||||
if err := repositories.DeletePost(postID); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete post"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Post deleted successfully"})
|
||||
}
|
||||
|
||||
// 获取文章历史记录
|
||||
func AdminGetPostHistory(c *gin.Context) {
|
||||
postID := c.Param("id")
|
||||
history, err := repositories.GetPostHistory(postID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get post history"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildPostHistoryResponses(history))
|
||||
}
|
||||
|
||||
// 获取指定版本的文章历史记录
|
||||
func AdminGetPostHistoryByVersion(c *gin.Context) {
|
||||
postID := c.Param("id")
|
||||
version := c.Param("version")
|
||||
|
||||
// 转换版本号为uint
|
||||
var versionUint uint
|
||||
_, err := fmt.Sscanf(version, "%d", &versionUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid version"})
|
||||
return
|
||||
}
|
||||
|
||||
history, err := repositories.GetPostHistoryByVersion(postID, versionUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get post history"})
|
||||
return
|
||||
}
|
||||
|
||||
if history == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "History not found"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildPostHistoryResponse(history))
|
||||
}
|
||||
145
server/handlers/role.go
Normal file
145
server/handlers/role.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
// 获取角色列表
|
||||
func AdminGetRoles(c *gin.Context) {
|
||||
roles, err := repositories.GetRoles()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get roles"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildRolesResponse(roles))
|
||||
}
|
||||
|
||||
// 创建角色
|
||||
func AdminCreateRole(c *gin.Context) {
|
||||
var role models.Role
|
||||
if err := c.ShouldBindJSON(&role); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 创建角色
|
||||
if err := repositories.CreateRole(&role); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create role"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Role created successfully"})
|
||||
}
|
||||
|
||||
// 更新角色
|
||||
func AdminUpdateRole(c *gin.Context) {
|
||||
roleID := c.Param("id")
|
||||
var role models.Role
|
||||
if err := c.ShouldBindJSON(&role); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 转换角色ID为uint
|
||||
var idUint uint
|
||||
_, err := fmt.Sscanf(roleID, "%d", &idUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置角色ID
|
||||
role.ID = idUint
|
||||
|
||||
// 更新角色
|
||||
if err := repositories.UpdateRole(&role); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update role"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Role updated successfully"})
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
func AdminDeleteRole(c *gin.Context) {
|
||||
roleID := c.Param("id")
|
||||
|
||||
// 转换角色ID为uint
|
||||
var idUint uint
|
||||
_, err := fmt.Sscanf(roleID, "%d", &idUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
if err := repositories.DeleteRole(idUint); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete role"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Role deleted successfully"})
|
||||
}
|
||||
|
||||
// 获取所有权限列表
|
||||
func AdminGetPermissions(c *gin.Context) {
|
||||
permissions, err := repositories.GetPermissions()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get permissions"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildPermissionsResponse(permissions))
|
||||
}
|
||||
|
||||
// 更新角色权限请求结构
|
||||
type UpdateRolePermissionsRequest struct {
|
||||
PermissionIDs []uint `json:"permissionIds" binding:"required"`
|
||||
}
|
||||
|
||||
// 更新角色的权限
|
||||
func AdminUpdateRolePermissions(c *gin.Context) {
|
||||
roleIDStr := c.Param("id")
|
||||
|
||||
// 转换角色ID
|
||||
var roleID uint
|
||||
id, err := strconv.ParseUint(roleIDStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role ID"})
|
||||
return
|
||||
}
|
||||
roleID = uint(id)
|
||||
|
||||
// 绑定请求数据
|
||||
var req UpdateRolePermissionsRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查角色是否存在
|
||||
role, err := repositories.GetRoleByID(roleID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check role existence"})
|
||||
return
|
||||
}
|
||||
if role == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Role not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// 更新权限
|
||||
if err := repositories.AssignPermissionsToRole(roleID, req.PermissionIDs); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update role permissions"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Role permissions updated successfully"})
|
||||
}
|
||||
54
server/handlers/runner.go
Normal file
54
server/handlers/runner.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/runner"
|
||||
)
|
||||
|
||||
type RunCodeRequest struct {
|
||||
Language string `json:"language" binding:"required"`
|
||||
Code string `json:"code" binding:"required"`
|
||||
}
|
||||
|
||||
func RunCode(c *gin.Context) {
|
||||
var req RunCodeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 对于前端语言,直接返回代码供前端渲染,或者提示不支持后端执行
|
||||
switch req.Language {
|
||||
case "html", "vue", "react", "css":
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"output": req.Code, // 或者返回 "Client-side rendering only"
|
||||
"isClient": true,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取运行器
|
||||
r, err := runner.GetRunner(req.Language)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置超时上下文 (例如 5 秒)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// 执行代码
|
||||
result, err := r.Run(ctx, req.Code)
|
||||
if err != nil {
|
||||
// 运行错误(如无法启动进程)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
67
server/handlers/setting.go
Normal file
67
server/handlers/setting.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
// 获取系统配置列表
|
||||
func AdminGetSettings(c *gin.Context) {
|
||||
settings, err := repositories.GetSettings()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get settings"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildSettingsResponse(settings))
|
||||
}
|
||||
|
||||
// 更新系统配置
|
||||
func AdminUpdateSetting(c *gin.Context) {
|
||||
var setting models.Setting
|
||||
if err := c.ShouldBindJSON(&setting); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 更新系统配置
|
||||
if err := repositories.UpdateSetting(&setting); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update setting"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Setting updated successfully"})
|
||||
}
|
||||
|
||||
// 创建系统配置
|
||||
func AdminCreateSetting(c *gin.Context) {
|
||||
var setting models.Setting
|
||||
if err := c.ShouldBindJSON(&setting); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 创建系统配置
|
||||
if err := repositories.CreateSetting(&setting); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create setting"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Setting created successfully"})
|
||||
}
|
||||
|
||||
// 删除系统配置
|
||||
func AdminDeleteSetting(c *gin.Context) {
|
||||
keyName := c.Param("key")
|
||||
|
||||
// 删除系统配置
|
||||
if err := repositories.DeleteSetting(keyName); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete setting"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Setting deleted successfully"})
|
||||
}
|
||||
106
server/handlers/snippet.go
Normal file
106
server/handlers/snippet.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
// 获取代码片段列表
|
||||
func GetSnippets(c *gin.Context) {
|
||||
// 从数据库获取所有代码片段
|
||||
snippets, err := repositories.GetSnippets()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch snippets"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
responses := repositories.BuildSnippetsResponse(snippets)
|
||||
|
||||
c.JSON(http.StatusOK, responses)
|
||||
}
|
||||
|
||||
func GetSnippet(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
// 从数据库获取代码片段
|
||||
snippet, err := repositories.GetSnippetByID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch snippet"})
|
||||
return
|
||||
}
|
||||
|
||||
if snippet == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Snippet not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response := repositories.BuildSnippetResponse(snippet)
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// 获取代码片段列表 (Admin)
|
||||
func AdminGetSnippets(c *gin.Context) {
|
||||
snippets, err := repositories.GetSnippets()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get snippets"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildSnippetsResponse(snippets))
|
||||
}
|
||||
|
||||
// 创建代码片段
|
||||
func AdminCreateSnippet(c *gin.Context) {
|
||||
var snippet models.Snippet
|
||||
if err := c.ShouldBindJSON(&snippet); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 创建代码片段
|
||||
if err := repositories.CreateSnippet(&snippet); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create snippet"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Snippet created successfully"})
|
||||
}
|
||||
|
||||
// 更新代码片段
|
||||
func AdminUpdateSnippet(c *gin.Context) {
|
||||
snippetID := c.Param("id")
|
||||
var snippet models.Snippet
|
||||
if err := c.ShouldBindJSON(&snippet); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置代码片段ID
|
||||
snippet.ID = snippetID
|
||||
|
||||
// 更新代码片段
|
||||
if err := repositories.UpdateSnippet(&snippet); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update snippet"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Snippet updated successfully"})
|
||||
}
|
||||
|
||||
// 删除代码片段
|
||||
func AdminDeleteSnippet(c *gin.Context) {
|
||||
snippetID := c.Param("id")
|
||||
|
||||
// 删除代码片段
|
||||
if err := repositories.DeleteSnippet(snippetID); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete snippet"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Snippet deleted successfully"})
|
||||
}
|
||||
132
server/handlers/tag.go
Normal file
132
server/handlers/tag.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
// 获取标签列表
|
||||
func GetTags(c *gin.Context) {
|
||||
// 从数据库获取所有标签
|
||||
tags, err := repositories.GetTags()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch tags"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
responses := repositories.BuildTagsResponse(tags)
|
||||
|
||||
c.JSON(http.StatusOK, responses)
|
||||
}
|
||||
|
||||
func GetTag(c *gin.Context) {
|
||||
// 解析标签ID
|
||||
idStr := c.Param("id")
|
||||
var id uint
|
||||
_, err := fmt.Sscanf(idStr, "%d", &id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tag ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 从数据库获取标签
|
||||
tag, err := repositories.GetTagByID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch tag"})
|
||||
return
|
||||
}
|
||||
|
||||
if tag == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Tag not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response := repositories.BuildTagResponse(tag)
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// 获取标签列表 (Admin)
|
||||
func AdminGetTags(c *gin.Context) {
|
||||
// 从数据库获取所有标签
|
||||
tags, err := repositories.GetTags()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get tags"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildTagsResponse(tags))
|
||||
}
|
||||
|
||||
// 创建标签
|
||||
func AdminCreateTag(c *gin.Context) {
|
||||
var tag models.Tag
|
||||
if err := c.ShouldBindJSON(&tag); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 创建标签
|
||||
if err := repositories.CreateTag(&tag); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create tag"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Tag created successfully"})
|
||||
}
|
||||
|
||||
// 更新标签
|
||||
func AdminUpdateTag(c *gin.Context) {
|
||||
tagID := c.Param("id")
|
||||
var tag models.Tag
|
||||
if err := c.ShouldBindJSON(&tag); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 转换标签ID为uint
|
||||
var idUint uint
|
||||
_, err := fmt.Sscanf(tagID, "%d", &idUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tag ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置标签ID
|
||||
tag.ID = idUint
|
||||
|
||||
// 更新标签
|
||||
if err := repositories.UpdateTag(&tag); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update tag"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Tag updated successfully"})
|
||||
}
|
||||
|
||||
// 删除标签
|
||||
func AdminDeleteTag(c *gin.Context) {
|
||||
tagID := c.Param("id")
|
||||
|
||||
// 转换标签ID为uint
|
||||
var idUint uint
|
||||
_, err := fmt.Sscanf(tagID, "%d", &idUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tag ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 删除标签
|
||||
if err := repositories.DeleteTag(idUint); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete tag"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Tag deleted successfully"})
|
||||
}
|
||||
129
server/handlers/user.go
Normal file
129
server/handlers/user.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// GetUsers 获取所有用户
|
||||
func AdminGetUsers(c *gin.Context) {
|
||||
users, err := repositories.GetUsers()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get users"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repositories.BuildUsersResponse(users))
|
||||
}
|
||||
|
||||
// GetUser 获取单个用户
|
||||
func AdminGetUser(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := repositories.GetUserByID(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user"})
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response := repositories.BuildUserResponse(user)
|
||||
|
||||
// 设置响应头
|
||||
c.Header("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
// 返回JSON响应
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// CreateUser 创建用户
|
||||
func AdminCreateUser(c *gin.Context) {
|
||||
var user models.User
|
||||
if err := c.ShouldBindJSON(&user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认密码并使用bcrypt哈希
|
||||
defaultPassword := "admin123"
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(defaultPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
|
||||
return
|
||||
}
|
||||
user.PasswordHash = string(hashedPassword)
|
||||
|
||||
// 创建用户
|
||||
if err := repositories.CreateUser(&user); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "User created successfully"})
|
||||
}
|
||||
|
||||
// UpdateUser 更新用户
|
||||
func AdminUpdateUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
var user models.User
|
||||
if err := c.ShouldBindJSON(&user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 转换用户ID为uint
|
||||
var idUint uint
|
||||
_, err := fmt.Sscanf(userID, "%d", &idUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置用户ID
|
||||
user.ID = idUint
|
||||
|
||||
// 更新用户
|
||||
if err := repositories.UpdateUser(&user); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "User updated successfully"})
|
||||
}
|
||||
|
||||
// DeleteUser 删除用户
|
||||
func AdminDeleteUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
|
||||
// 转换用户ID为uint
|
||||
var idUint uint
|
||||
_, err := fmt.Sscanf(userID, "%d", &idUint)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
if err := repositories.DeleteUser(idUint); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete user"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "User deleted successfully"})
|
||||
}
|
||||
130
server/handlers/work.go
Normal file
130
server/handlers/work.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
"github.com/niangaodev/art-code/repositories"
|
||||
)
|
||||
|
||||
// 获取作品列表
|
||||
func GetWorks(c *gin.Context) {
|
||||
// 从数据库获取所有作品
|
||||
works, err := repositories.GetWorks()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch works"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
var responses []interface{}
|
||||
for _, work := range works {
|
||||
response, err := repositories.BuildWorkResponse(&work)
|
||||
if err != nil {
|
||||
log.Printf("Error building work response: %v", err)
|
||||
continue
|
||||
}
|
||||
responses = append(responses, response)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, responses)
|
||||
}
|
||||
|
||||
func GetWork(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
// 从数据库获取作品
|
||||
work, err := repositories.GetWorkByID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch work"})
|
||||
return
|
||||
}
|
||||
|
||||
if work == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Work not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response, err := repositories.BuildWorkResponse(work)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to build work response"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// 获取作品列表 (Admin)
|
||||
func AdminGetWorks(c *gin.Context) {
|
||||
works, err := repositories.GetWorks()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get works"})
|
||||
return
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
var responses []interface{}
|
||||
for _, work := range works {
|
||||
response, err := repositories.BuildWorkResponse(&work)
|
||||
if err != nil {
|
||||
log.Printf("Error building work response: %v", err)
|
||||
continue
|
||||
}
|
||||
responses = append(responses, response)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, responses)
|
||||
}
|
||||
|
||||
// 创建作品
|
||||
func AdminCreateWork(c *gin.Context) {
|
||||
var work models.Work
|
||||
if err := c.ShouldBindJSON(&work); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 创建作品
|
||||
if err := repositories.CreateWork(&work); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create work"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Work created successfully"})
|
||||
}
|
||||
|
||||
// 更新作品
|
||||
func AdminUpdateWork(c *gin.Context) {
|
||||
workID := c.Param("id")
|
||||
var work models.Work
|
||||
if err := c.ShouldBindJSON(&work); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置作品ID
|
||||
work.ID = workID
|
||||
|
||||
// 更新作品
|
||||
if err := repositories.UpdateWork(&work); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update work"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Work updated successfully"})
|
||||
}
|
||||
|
||||
// 删除作品
|
||||
func AdminDeleteWork(c *gin.Context) {
|
||||
workID := c.Param("id")
|
||||
|
||||
// 删除作品
|
||||
if err := repositories.DeleteWork(workID); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete work"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Work deleted successfully"})
|
||||
}
|
||||
Reference in New Issue
Block a user