初始化
This commit is contained in:
109
server/repositories/operation_log_repository.go
Normal file
109
server/repositories/operation_log_repository.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// CreateOperationLog 创建操作日志
|
||||
func CreateOperationLog(operationLog *models.OperationLog) error {
|
||||
query := `
|
||||
INSERT INTO operation_logs (user_id, username, ip, path, method, params, status, duration, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
operationLog.UserID,
|
||||
operationLog.Username,
|
||||
operationLog.IP,
|
||||
operationLog.Path,
|
||||
operationLog.Method,
|
||||
operationLog.Params,
|
||||
operationLog.Status,
|
||||
operationLog.Duration,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error creating operation log: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOperationLogs 获取操作日志列表
|
||||
func GetOperationLogs(page, pageSize int) ([]models.OperationLog, int64, error) {
|
||||
// 计算偏移量
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
// 获取总记录数
|
||||
var total int64
|
||||
countQuery := "SELECT COUNT(*) FROM operation_logs"
|
||||
if err := config.DB.QueryRow(countQuery).Scan(&total); err != nil {
|
||||
log.Printf("Error counting operation logs: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取分页数据
|
||||
query := `
|
||||
SELECT id, user_id, username, ip, path, method, params, status, duration, created_at
|
||||
FROM operation_logs
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`
|
||||
rows, err := config.DB.Query(query, pageSize, offset)
|
||||
if err != nil {
|
||||
log.Printf("Error querying operation logs: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var logs []models.OperationLog
|
||||
for rows.Next() {
|
||||
var operationLog models.OperationLog
|
||||
if err := rows.Scan(
|
||||
&operationLog.ID,
|
||||
&operationLog.UserID,
|
||||
&operationLog.Username,
|
||||
&operationLog.IP,
|
||||
&operationLog.Path,
|
||||
&operationLog.Method,
|
||||
&operationLog.Params,
|
||||
&operationLog.Status,
|
||||
&operationLog.Duration,
|
||||
&operationLog.CreatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning operation log: %v", err)
|
||||
continue
|
||||
}
|
||||
logs = append(logs, operationLog)
|
||||
}
|
||||
|
||||
return logs, total, nil
|
||||
}
|
||||
|
||||
// BuildOperationLogResponse 构建操作日志响应
|
||||
func BuildOperationLogResponse(log *models.OperationLog) *models.OperationLogResponse {
|
||||
return &models.OperationLogResponse{
|
||||
ID: log.ID,
|
||||
UserID: log.UserID,
|
||||
Username: log.Username,
|
||||
IP: log.IP,
|
||||
Path: log.Path,
|
||||
Method: log.Method,
|
||||
Params: log.Params,
|
||||
Status: log.Status,
|
||||
Duration: log.Duration,
|
||||
CreatedAt: log.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// BuildOperationLogsResponse 构建操作日志列表响应
|
||||
func BuildOperationLogsResponse(logs []models.OperationLog) []models.OperationLogResponse {
|
||||
var responses []models.OperationLogResponse
|
||||
for _, log := range logs {
|
||||
responses = append(responses, *BuildOperationLogResponse(&log))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
80
server/repositories/permission_repository.go
Normal file
80
server/repositories/permission_repository.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetPermissions 获取所有权限
|
||||
func GetPermissions() ([]models.Permission, error) {
|
||||
query := "SELECT id, name, resource, action, created_at, updated_at FROM permissions"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error getting permissions: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var permissions []models.Permission
|
||||
for rows.Next() {
|
||||
var permission models.Permission
|
||||
if err := rows.Scan(&permission.ID, &permission.Name, &permission.Resource, &permission.Action, &permission.CreatedAt, &permission.UpdatedAt); err != nil {
|
||||
log.Printf("Error scanning permission: %v", err)
|
||||
continue
|
||||
}
|
||||
permissions = append(permissions, permission)
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
// GetPermissionsByRoleID 获取指定角色的权限
|
||||
func GetPermissionsByRoleID(roleID uint) ([]models.Permission, error) {
|
||||
query := `
|
||||
SELECT p.id, p.name, p.resource, p.action, p.created_at, p.updated_at
|
||||
FROM permissions p
|
||||
JOIN role_permissions rp ON p.id = rp.permission_id
|
||||
WHERE rp.role_id = ?
|
||||
`
|
||||
rows, err := config.DB.Query(query, roleID)
|
||||
if err != nil {
|
||||
log.Printf("Error getting permissions by role id: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var permissions []models.Permission
|
||||
for rows.Next() {
|
||||
var permission models.Permission
|
||||
if err := rows.Scan(&permission.ID, &permission.Name, &permission.Resource, &permission.Action, &permission.CreatedAt, &permission.UpdatedAt); err != nil {
|
||||
log.Printf("Error scanning permission: %v", err)
|
||||
continue
|
||||
}
|
||||
permissions = append(permissions, permission)
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
// BuildPermissionResponse 构建权限响应
|
||||
func BuildPermissionResponse(permission *models.Permission) *models.PermissionResponse {
|
||||
return &models.PermissionResponse{
|
||||
ID: permission.ID,
|
||||
Name: permission.Name,
|
||||
Resource: permission.Resource,
|
||||
Action: permission.Action,
|
||||
CreatedAt: permission.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: permission.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// BuildPermissionsResponse 构建权限列表响应
|
||||
func BuildPermissionsResponse(permissions []models.Permission) []models.PermissionResponse {
|
||||
var responses []models.PermissionResponse
|
||||
for _, permission := range permissions {
|
||||
responses = append(responses, *BuildPermissionResponse(&permission))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
351
server/repositories/post_repository.go
Normal file
351
server/repositories/post_repository.go
Normal file
@@ -0,0 +1,351 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetPosts 获取所有博客文章
|
||||
func GetPosts() ([]models.Post, error) {
|
||||
query := "SELECT id, title, category, date, excerpt, content, read_count, is_published, created_at, updated_at FROM posts WHERE is_published = 1 ORDER BY date DESC"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error querying posts: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var posts []models.Post
|
||||
for rows.Next() {
|
||||
var post models.Post
|
||||
if err := rows.Scan(
|
||||
&post.ID,
|
||||
&post.Title,
|
||||
&post.Category,
|
||||
&post.Date,
|
||||
&post.Excerpt,
|
||||
&post.Content,
|
||||
&post.ReadCount,
|
||||
&post.IsPublished,
|
||||
&post.CreatedAt,
|
||||
&post.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning post: %v", err)
|
||||
continue
|
||||
}
|
||||
posts = append(posts, post)
|
||||
}
|
||||
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
// GetPostByID 根据ID获取博客文章
|
||||
func GetPostByID(id string) (*models.Post, error) {
|
||||
query := "SELECT id, title, category, date, excerpt, content, read_count, is_published, created_at, updated_at FROM posts WHERE id = ? AND is_published = 1"
|
||||
row := config.DB.QueryRow(query, id)
|
||||
|
||||
var post models.Post
|
||||
if err := row.Scan(
|
||||
&post.ID,
|
||||
&post.Title,
|
||||
&post.Category,
|
||||
&post.Date,
|
||||
&post.Excerpt,
|
||||
&post.Content,
|
||||
&post.ReadCount,
|
||||
&post.IsPublished,
|
||||
&post.CreatedAt,
|
||||
&post.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning post by ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 更新阅读量
|
||||
updateReadCountQuery := "UPDATE posts SET read_count = read_count + 1 WHERE id = ?"
|
||||
if _, err := config.DB.Exec(updateReadCountQuery, id); err != nil {
|
||||
log.Printf("Error updating post read count: %v", err)
|
||||
}
|
||||
|
||||
return &post, nil
|
||||
}
|
||||
|
||||
// GetAllPosts 获取所有博客文章(包括未发布的)
|
||||
func GetAllPosts() ([]models.Post, error) {
|
||||
query := "SELECT id, title, category, date, excerpt, content, read_count, is_published, created_at, updated_at FROM posts ORDER BY date DESC"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error querying all posts: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var posts []models.Post
|
||||
for rows.Next() {
|
||||
var post models.Post
|
||||
if err := rows.Scan(
|
||||
&post.ID,
|
||||
&post.Title,
|
||||
&post.Category,
|
||||
&post.Date,
|
||||
&post.Excerpt,
|
||||
&post.Content,
|
||||
&post.ReadCount,
|
||||
&post.IsPublished,
|
||||
&post.CreatedAt,
|
||||
&post.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning post: %v", err)
|
||||
continue
|
||||
}
|
||||
posts = append(posts, post)
|
||||
}
|
||||
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
// CreatePost 创建博客文章
|
||||
func CreatePost(post *models.Post) error {
|
||||
query := `
|
||||
INSERT INTO posts (id, title, category, date, excerpt, content, is_published, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
post.ID,
|
||||
post.Title,
|
||||
post.Category,
|
||||
post.Date,
|
||||
post.Excerpt,
|
||||
post.Content,
|
||||
post.IsPublished,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error creating post: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePost 更新博客文章
|
||||
func UpdatePost(post *models.Post) error {
|
||||
query := `
|
||||
UPDATE posts SET title = ?, category = ?, date = ?, excerpt = ?, content = ?, is_published = ?, updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
post.Title,
|
||||
post.Category,
|
||||
post.Date,
|
||||
post.Excerpt,
|
||||
post.Content,
|
||||
post.IsPublished,
|
||||
post.ID,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error updating post: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePost 删除博客文章
|
||||
func DeletePost(id string) error {
|
||||
query := "DELETE FROM posts WHERE id = ?"
|
||||
_, err := config.DB.Exec(query, id)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting post: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPostCount 获取文章总数
|
||||
func GetPostCount() (int, error) {
|
||||
var count int
|
||||
query := "SELECT COUNT(*) FROM posts"
|
||||
row := config.DB.QueryRow(query)
|
||||
|
||||
err := row.Scan(&count)
|
||||
if err != nil {
|
||||
log.Printf("Error getting post count: %v", err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// BuildPostResponse 构建博客文章响应
|
||||
func BuildPostResponse(post *models.Post, includeContent bool) *models.PostResponse {
|
||||
response := &models.PostResponse{
|
||||
ID: post.ID,
|
||||
Title: post.Title,
|
||||
Category: post.Category,
|
||||
Date: post.Date.Format("2006-01-02"),
|
||||
Excerpt: post.Excerpt,
|
||||
}
|
||||
|
||||
if includeContent {
|
||||
response.Content = post.Content
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// BuildPostsResponse 构建博客文章列表响应
|
||||
func BuildPostsResponse(posts []models.Post) []models.PostResponse {
|
||||
var responses []models.PostResponse
|
||||
for _, post := range posts {
|
||||
responses = append(responses, *BuildPostResponse(&post, false))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// SavePostHistory 保存文章历史记录
|
||||
func SavePostHistory(post *models.Post, modifiedBy uint) error {
|
||||
// 获取当前最大版本号
|
||||
var maxVersion uint
|
||||
query := "SELECT COALESCE(MAX(version), 0) FROM post_history WHERE post_id = ?"
|
||||
if err := config.DB.QueryRow(query, post.ID).Scan(&maxVersion); err != nil {
|
||||
log.Printf("Error getting max version: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 插入新的历史记录
|
||||
insertQuery := `
|
||||
INSERT INTO post_history (
|
||||
post_id, version, title, category, date, excerpt, content,
|
||||
is_published, modified_by, modified_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
insertQuery,
|
||||
post.ID,
|
||||
maxVersion+1,
|
||||
post.Title,
|
||||
post.Category,
|
||||
post.Date,
|
||||
post.Excerpt,
|
||||
post.Content,
|
||||
post.IsPublished,
|
||||
modifiedBy,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error saving post history: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPostHistory 获取文章历史记录
|
||||
func GetPostHistory(postID string) ([]models.PostHistory, error) {
|
||||
query := `
|
||||
SELECT id, post_id, version, title, category, date, excerpt, content,
|
||||
is_published, modified_by, modified_at, created_at
|
||||
FROM post_history
|
||||
WHERE post_id = ?
|
||||
ORDER BY version DESC
|
||||
`
|
||||
rows, err := config.DB.Query(query, postID)
|
||||
if err != nil {
|
||||
log.Printf("Error querying post history: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var history []models.PostHistory
|
||||
for rows.Next() {
|
||||
var h models.PostHistory
|
||||
if err := rows.Scan(
|
||||
&h.ID,
|
||||
&h.PostID,
|
||||
&h.Version,
|
||||
&h.Title,
|
||||
&h.Category,
|
||||
&h.Date,
|
||||
&h.Excerpt,
|
||||
&h.Content,
|
||||
&h.IsPublished,
|
||||
&h.ModifiedBy,
|
||||
&h.ModifiedAt,
|
||||
&h.CreatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning post history: %v", err)
|
||||
continue
|
||||
}
|
||||
history = append(history, h)
|
||||
}
|
||||
|
||||
return history, nil
|
||||
}
|
||||
|
||||
// GetPostHistoryByVersion 获取指定版本的文章历史记录
|
||||
func GetPostHistoryByVersion(postID string, version uint) (*models.PostHistory, error) {
|
||||
query := `
|
||||
SELECT id, post_id, version, title, category, date, excerpt, content,
|
||||
is_published, modified_by, modified_at, created_at
|
||||
FROM post_history
|
||||
WHERE post_id = ? AND version = ?
|
||||
`
|
||||
row := config.DB.QueryRow(query, postID, version)
|
||||
|
||||
var h models.PostHistory
|
||||
if err := row.Scan(
|
||||
&h.ID,
|
||||
&h.PostID,
|
||||
&h.Version,
|
||||
&h.Title,
|
||||
&h.Category,
|
||||
&h.Date,
|
||||
&h.Excerpt,
|
||||
&h.Content,
|
||||
&h.IsPublished,
|
||||
&h.ModifiedBy,
|
||||
&h.ModifiedAt,
|
||||
&h.CreatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning post history by version: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &h, nil
|
||||
}
|
||||
|
||||
// BuildPostHistoryResponse 构建文章历史记录响应
|
||||
func BuildPostHistoryResponse(history *models.PostHistory) *models.PostHistoryResponse {
|
||||
return &models.PostHistoryResponse{
|
||||
ID: history.ID,
|
||||
PostID: history.PostID,
|
||||
Version: history.Version,
|
||||
Title: history.Title,
|
||||
Category: history.Category,
|
||||
Date: history.Date.Format("2006-01-02"),
|
||||
IsPublished: history.IsPublished,
|
||||
ModifiedBy: history.ModifiedBy,
|
||||
ModifiedAt: history.ModifiedAt.Format("2006-01-02 15:04:05"),
|
||||
CreatedAt: history.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// BuildPostHistoryResponses 构建文章历史记录列表响应
|
||||
func BuildPostHistoryResponses(history []models.PostHistory) []models.PostHistoryResponse {
|
||||
var responses []models.PostHistoryResponse
|
||||
for _, h := range history {
|
||||
responses = append(responses, *BuildPostHistoryResponse(&h))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
166
server/repositories/role_repository.go
Normal file
166
server/repositories/role_repository.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetRoles 获取所有角色
|
||||
func GetRoles() ([]models.Role, error) {
|
||||
query := "SELECT id, name, description, created_at, updated_at FROM roles"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error getting roles: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var roles []models.Role
|
||||
for rows.Next() {
|
||||
var role models.Role
|
||||
if err := rows.Scan(&role.ID, &role.Name, &role.Description, &role.CreatedAt, &role.UpdatedAt); err != nil {
|
||||
log.Printf("Error scanning role: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取权限
|
||||
permissions, _ := GetPermissionsByRoleID(role.ID)
|
||||
role.Permissions = permissions
|
||||
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
// GetRoleByID 根据ID获取角色
|
||||
func GetRoleByID(id uint) (*models.Role, error) {
|
||||
query := "SELECT id, name, description, created_at, updated_at FROM roles WHERE id = ?"
|
||||
row := config.DB.QueryRow(query, id)
|
||||
|
||||
var role models.Role
|
||||
if err := row.Scan(&role.ID, &role.Name, &role.Description, &role.CreatedAt, &role.UpdatedAt); err != nil {
|
||||
log.Printf("Error getting role by ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取权限
|
||||
permissions, _ := GetPermissionsByRoleID(role.ID)
|
||||
role.Permissions = permissions
|
||||
|
||||
return &role, nil
|
||||
}
|
||||
|
||||
// GetRoleByName 根据名称获取角色
|
||||
func GetRoleByName(name string) (*models.Role, error) {
|
||||
query := "SELECT id, name, description, created_at, updated_at FROM roles WHERE name = ?"
|
||||
row := config.DB.QueryRow(query, name)
|
||||
|
||||
var role models.Role
|
||||
if err := row.Scan(&role.ID, &role.Name, &role.Description, &role.CreatedAt, &role.UpdatedAt); err != nil {
|
||||
log.Printf("Error getting role by name: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &role, nil
|
||||
}
|
||||
|
||||
// CreateRole 创建角色
|
||||
func CreateRole(role *models.Role) error {
|
||||
query := "INSERT INTO roles (name, description, created_at, updated_at) VALUES (?, ?, NOW(), NOW())"
|
||||
result, err := config.DB.Exec(query, role.Name, role.Description)
|
||||
if err != nil {
|
||||
log.Printf("Error creating role: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role.ID = uint(id)
|
||||
role.CreatedAt = time.Now()
|
||||
role.UpdatedAt = time.Now()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateRole 更新角色
|
||||
func UpdateRole(role *models.Role) error {
|
||||
query := "UPDATE roles SET name = ?, description = ?, updated_at = NOW() WHERE id = ?"
|
||||
_, err := config.DB.Exec(query, role.Name, role.Description, role.ID)
|
||||
if err != nil {
|
||||
log.Printf("Error updating role: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteRole 删除角色
|
||||
func DeleteRole(id uint) error {
|
||||
query := "DELETE FROM roles WHERE id = ?"
|
||||
_, err := config.DB.Exec(query, id)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting role: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssignPermissionsToRole 给角色分配权限
|
||||
func AssignPermissionsToRole(roleID uint, permissionIDs []uint) error {
|
||||
// 开启事务
|
||||
tx, err := config.DB.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 先删除旧权限
|
||||
_, err = tx.Exec("DELETE FROM role_permissions WHERE role_id = ?", roleID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 插入新权限
|
||||
stmt, err := tx.Prepare("INSERT INTO role_permissions (role_id, permission_id) VALUES (?, ?)")
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
for _, permID := range permissionIDs {
|
||||
_, err = stmt.Exec(roleID, permID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// BuildRoleResponse 构建角色响应
|
||||
func BuildRoleResponse(role *models.Role) *models.RoleResponse {
|
||||
return &models.RoleResponse{
|
||||
ID: role.ID,
|
||||
Name: role.Name,
|
||||
Description: role.Description,
|
||||
Permissions: BuildPermissionsResponse(role.Permissions),
|
||||
CreatedAt: role.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: role.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// BuildRolesResponse 构建角色列表响应
|
||||
func BuildRolesResponse(roles []models.Role) []models.RoleResponse {
|
||||
var responses []models.RoleResponse
|
||||
for _, role := range roles {
|
||||
responses = append(responses, *BuildRoleResponse(&role))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
144
server/repositories/setting_repository.go
Normal file
144
server/repositories/setting_repository.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetSettings 获取所有系统配置
|
||||
func GetSettings() ([]models.Setting, error) {
|
||||
query := "SELECT id, key_name, value, description, created_at, updated_at FROM settings ORDER BY key_name"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error querying settings: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var settings []models.Setting
|
||||
for rows.Next() {
|
||||
var setting models.Setting
|
||||
if err := rows.Scan(
|
||||
&setting.ID,
|
||||
&setting.KeyName,
|
||||
&setting.Value,
|
||||
&setting.Description,
|
||||
&setting.CreatedAt,
|
||||
&setting.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning setting: %v", err)
|
||||
continue
|
||||
}
|
||||
settings = append(settings, setting)
|
||||
}
|
||||
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// GetSettingByKey 根据键名获取系统配置
|
||||
func GetSettingByKey(keyName string) (*models.Setting, error) {
|
||||
query := "SELECT id, key_name, value, description, created_at, updated_at FROM settings WHERE key_name = ?"
|
||||
row := config.DB.QueryRow(query, keyName)
|
||||
|
||||
var setting models.Setting
|
||||
if err := row.Scan(
|
||||
&setting.ID,
|
||||
&setting.KeyName,
|
||||
&setting.Value,
|
||||
&setting.Description,
|
||||
&setting.CreatedAt,
|
||||
&setting.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning setting by key: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &setting, nil
|
||||
}
|
||||
|
||||
// UpdateSetting 更新系统配置
|
||||
func UpdateSetting(setting *models.Setting) error {
|
||||
query := `
|
||||
UPDATE settings SET value = ?, description = ?, updated_at = NOW()
|
||||
WHERE key_name = ?
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
setting.Value,
|
||||
setting.Description,
|
||||
setting.KeyName,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error updating setting: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateSetting 创建系统配置
|
||||
func CreateSetting(setting *models.Setting) error {
|
||||
query := `
|
||||
INSERT INTO settings (key_name, value, description, created_at, updated_at)
|
||||
VALUES (?, ?, ?, NOW(), NOW())
|
||||
`
|
||||
result, err := config.DB.Exec(
|
||||
query,
|
||||
setting.KeyName,
|
||||
setting.Value,
|
||||
setting.Description,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error creating setting: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取自增ID
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
log.Printf("Error getting last insert ID: %v", err)
|
||||
return err
|
||||
}
|
||||
setting.ID = uint(id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSetting 删除系统配置
|
||||
func DeleteSetting(keyName string) error {
|
||||
query := "DELETE FROM settings WHERE key_name = ?"
|
||||
_, err := config.DB.Exec(query, keyName)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting setting: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildSettingResponse 构建系统配置响应
|
||||
func BuildSettingResponse(setting *models.Setting) *models.SettingResponse {
|
||||
return &models.SettingResponse{
|
||||
ID: setting.ID,
|
||||
KeyName: setting.KeyName,
|
||||
Value: setting.Value,
|
||||
Description: setting.Description,
|
||||
CreatedAt: setting.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: setting.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// BuildSettingsResponse 构建系统配置列表响应
|
||||
func BuildSettingsResponse(settings []models.Setting) []models.SettingResponse {
|
||||
var responses []models.SettingResponse
|
||||
for _, setting := range settings {
|
||||
responses = append(responses, *BuildSettingResponse(&setting))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
163
server/repositories/snippet_repository.go
Normal file
163
server/repositories/snippet_repository.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetSnippets 获取所有代码片段
|
||||
func GetSnippets() ([]models.Snippet, error) {
|
||||
query := "SELECT id, title, code, type, description, view_count, created_at, updated_at FROM snippets ORDER BY created_at DESC"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error querying snippets: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var snippets []models.Snippet
|
||||
for rows.Next() {
|
||||
var snippet models.Snippet
|
||||
if err := rows.Scan(
|
||||
&snippet.ID,
|
||||
&snippet.Title,
|
||||
&snippet.Code,
|
||||
&snippet.Type,
|
||||
&snippet.Description,
|
||||
&snippet.ViewCount,
|
||||
&snippet.CreatedAt,
|
||||
&snippet.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning snippet: %v", err)
|
||||
continue
|
||||
}
|
||||
snippets = append(snippets, snippet)
|
||||
}
|
||||
|
||||
return snippets, nil
|
||||
}
|
||||
|
||||
// GetSnippetByID 根据ID获取代码片段
|
||||
func GetSnippetByID(id string) (*models.Snippet, error) {
|
||||
query := "SELECT id, title, code, type, description, view_count, created_at, updated_at FROM snippets WHERE id = ?"
|
||||
row := config.DB.QueryRow(query, id)
|
||||
|
||||
var snippet models.Snippet
|
||||
if err := row.Scan(
|
||||
&snippet.ID,
|
||||
&snippet.Title,
|
||||
&snippet.Code,
|
||||
&snippet.Type,
|
||||
&snippet.Description,
|
||||
&snippet.ViewCount,
|
||||
&snippet.CreatedAt,
|
||||
&snippet.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning snippet by ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 更新查看次数
|
||||
updateViewCountQuery := "UPDATE snippets SET view_count = view_count + 1 WHERE id = ?"
|
||||
if _, err := config.DB.Exec(updateViewCountQuery, id); err != nil {
|
||||
log.Printf("Error updating snippet view count: %v", err)
|
||||
}
|
||||
|
||||
return &snippet, nil
|
||||
}
|
||||
|
||||
// BuildSnippetResponse 构建代码片段响应
|
||||
func BuildSnippetResponse(snippet *models.Snippet) *models.SnippetResponse {
|
||||
return &models.SnippetResponse{
|
||||
ID: snippet.ID,
|
||||
Title: snippet.Title,
|
||||
Code: snippet.Code,
|
||||
Type: snippet.Type,
|
||||
}
|
||||
}
|
||||
|
||||
// BuildSnippetsResponse 构建代码片段列表响应
|
||||
func BuildSnippetsResponse(snippets []models.Snippet) []models.SnippetResponse {
|
||||
var responses []models.SnippetResponse
|
||||
for _, snippet := range snippets {
|
||||
responses = append(responses, *BuildSnippetResponse(&snippet))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// CreateSnippet 创建代码片段
|
||||
func CreateSnippet(snippet *models.Snippet) error {
|
||||
query := `
|
||||
INSERT INTO snippets (id, title, code, type, description, view_count, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, 0, NOW(), NOW())
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
snippet.ID,
|
||||
snippet.Title,
|
||||
snippet.Code,
|
||||
snippet.Type,
|
||||
snippet.Description,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error creating snippet: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSnippet 更新代码片段
|
||||
func UpdateSnippet(snippet *models.Snippet) error {
|
||||
query := `
|
||||
UPDATE snippets SET title = ?, code = ?, type = ?, description = ?, updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
snippet.Title,
|
||||
snippet.Code,
|
||||
snippet.Type,
|
||||
snippet.Description,
|
||||
snippet.ID,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error updating snippet: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSnippet 删除代码片段
|
||||
func DeleteSnippet(id string) error {
|
||||
query := "DELETE FROM snippets WHERE id = ?"
|
||||
_, err := config.DB.Exec(query, id)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting snippet: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSnippetCount 获取代码片段总数
|
||||
func GetSnippetCount() (int, error) {
|
||||
var count int
|
||||
query := "SELECT COUNT(*) FROM snippets"
|
||||
row := config.DB.QueryRow(query)
|
||||
|
||||
err := row.Scan(&count)
|
||||
if err != nil {
|
||||
log.Printf("Error getting snippet count: %v", err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
264
server/repositories/tag_repository.go
Normal file
264
server/repositories/tag_repository.go
Normal file
@@ -0,0 +1,264 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetTags 获取所有标签
|
||||
func GetTags() ([]models.Tag, error) {
|
||||
query := "SELECT id, name, slug, created_at, updated_at FROM tags ORDER BY name ASC"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error querying tags: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var tags []models.Tag
|
||||
for rows.Next() {
|
||||
var tag models.Tag
|
||||
if err := rows.Scan(
|
||||
&tag.ID,
|
||||
&tag.Name,
|
||||
&tag.Slug,
|
||||
&tag.CreatedAt,
|
||||
&tag.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning tag: %v", err)
|
||||
continue
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
// GetTagByID 根据ID获取标签
|
||||
func GetTagByID(id uint) (*models.Tag, error) {
|
||||
query := "SELECT id, name, slug, created_at, updated_at FROM tags WHERE id = ?"
|
||||
row := config.DB.QueryRow(query, id)
|
||||
|
||||
var tag models.Tag
|
||||
if err := row.Scan(
|
||||
&tag.ID,
|
||||
&tag.Name,
|
||||
&tag.Slug,
|
||||
&tag.CreatedAt,
|
||||
&tag.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning tag by ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tag, nil
|
||||
}
|
||||
|
||||
// GetTagBySlug 根据Slug获取标签
|
||||
func GetTagBySlug(slug string) (*models.Tag, error) {
|
||||
query := "SELECT id, name, slug, created_at, updated_at FROM tags WHERE slug = ?"
|
||||
row := config.DB.QueryRow(query, slug)
|
||||
|
||||
var tag models.Tag
|
||||
if err := row.Scan(
|
||||
&tag.ID,
|
||||
&tag.Name,
|
||||
&tag.Slug,
|
||||
&tag.CreatedAt,
|
||||
&tag.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning tag by slug: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tag, nil
|
||||
}
|
||||
|
||||
// CreateTag 创建标签
|
||||
func CreateTag(tag *models.Tag) error {
|
||||
query := `
|
||||
INSERT INTO tags (name, slug, created_at, updated_at)
|
||||
VALUES (?, ?, NOW(), NOW())
|
||||
`
|
||||
result, err := config.DB.Exec(
|
||||
query,
|
||||
tag.Name,
|
||||
tag.Slug,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error creating tag: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取自增ID
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
log.Printf("Error getting last insert ID: %v", err)
|
||||
return err
|
||||
}
|
||||
tag.ID = uint(id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateTag 更新标签
|
||||
func UpdateTag(tag *models.Tag) error {
|
||||
query := `
|
||||
UPDATE tags SET name = ?, slug = ?, updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
tag.Name,
|
||||
tag.Slug,
|
||||
tag.ID,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error updating tag: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteTag 删除标签
|
||||
func DeleteTag(id uint) error {
|
||||
// 先删除关联的文章标签关系
|
||||
query := "DELETE FROM post_tags WHERE tag_id = ?"
|
||||
_, err := config.DB.Exec(query, id)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting post-tag relationships: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 再删除标签
|
||||
query = "DELETE FROM tags WHERE id = ?"
|
||||
_, err = config.DB.Exec(query, id)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting tag: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTagsByPostID 根据文章ID获取标签
|
||||
func GetTagsByPostID(postID string) ([]models.Tag, error) {
|
||||
query := `
|
||||
SELECT t.id, t.name, t.slug, t.created_at, t.updated_at
|
||||
FROM tags t
|
||||
JOIN post_tags pt ON t.id = pt.tag_id
|
||||
WHERE pt.post_id = ?
|
||||
ORDER BY t.name ASC
|
||||
`
|
||||
rows, err := config.DB.Query(query, postID)
|
||||
if err != nil {
|
||||
log.Printf("Error querying tags by post ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var tags []models.Tag
|
||||
for rows.Next() {
|
||||
var tag models.Tag
|
||||
if err := rows.Scan(
|
||||
&tag.ID,
|
||||
&tag.Name,
|
||||
&tag.Slug,
|
||||
&tag.CreatedAt,
|
||||
&tag.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning tag: %v", err)
|
||||
continue
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
// AddTagToPost 为文章添加标签
|
||||
func AddTagToPost(postID string, tagID uint) error {
|
||||
query := `
|
||||
INSERT IGNORE INTO post_tags (post_id, tag_id, created_at)
|
||||
VALUES (?, ?, NOW())
|
||||
`
|
||||
_, err := config.DB.Exec(query, postID, tagID)
|
||||
if err != nil {
|
||||
log.Printf("Error adding tag to post: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTagFromPost 从文章移除标签
|
||||
func RemoveTagFromPost(postID string, tagID uint) error {
|
||||
query := "DELETE FROM post_tags WHERE post_id = ? AND tag_id = ?"
|
||||
_, err := config.DB.Exec(query, postID, tagID)
|
||||
if err != nil {
|
||||
log.Printf("Error removing tag from post: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPostsByTagID 根据标签ID获取文章
|
||||
func GetPostsByTagID(tagID uint) ([]models.Post, error) {
|
||||
query := `
|
||||
SELECT p.id, p.title, p.category, p.date, p.excerpt, p.content, p.read_count, p.is_published, p.created_at, p.updated_at
|
||||
FROM posts p
|
||||
JOIN post_tags pt ON p.id = pt.post_id
|
||||
WHERE pt.tag_id = ? AND p.is_published = 1
|
||||
ORDER BY p.date DESC
|
||||
`
|
||||
rows, err := config.DB.Query(query, tagID)
|
||||
if err != nil {
|
||||
log.Printf("Error querying posts by tag ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var posts []models.Post
|
||||
for rows.Next() {
|
||||
var post models.Post
|
||||
if err := rows.Scan(
|
||||
&post.ID,
|
||||
&post.Title,
|
||||
&post.Category,
|
||||
&post.Date,
|
||||
&post.Excerpt,
|
||||
&post.Content,
|
||||
&post.ReadCount,
|
||||
&post.IsPublished,
|
||||
&post.CreatedAt,
|
||||
&post.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning post: %v", err)
|
||||
continue
|
||||
}
|
||||
posts = append(posts, post)
|
||||
}
|
||||
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
// BuildTagsResponse 构建标签列表响应
|
||||
func BuildTagsResponse(tags []models.Tag) []models.Tag {
|
||||
return tags
|
||||
}
|
||||
|
||||
// BuildTagResponse 构建标签响应
|
||||
func BuildTagResponse(tag *models.Tag) *models.Tag {
|
||||
return tag
|
||||
}
|
||||
293
server/repositories/user_repository.go
Normal file
293
server/repositories/user_repository.go
Normal file
@@ -0,0 +1,293 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetUserByUsername 根据用户名获取用户
|
||||
func GetUserByUsername(username string) (*models.User, error) {
|
||||
query := `
|
||||
SELECT u.id, u.username, u.email, u.password_hash, u.role_id, COALESCE(r.name, u.role), u.is_active, u.created_at, u.updated_at
|
||||
FROM users u
|
||||
LEFT JOIN roles r ON u.role_id = r.id
|
||||
WHERE u.username = ?
|
||||
`
|
||||
row := config.DB.QueryRow(query, username)
|
||||
|
||||
var user models.User
|
||||
var roleID sql.NullInt64 // Handle nullable role_id
|
||||
var roleName sql.NullString // Handle nullable role name
|
||||
|
||||
if err := row.Scan(
|
||||
&user.ID,
|
||||
&user.Username,
|
||||
&user.Email,
|
||||
&user.PasswordHash,
|
||||
&roleID,
|
||||
&roleName,
|
||||
&user.IsActive,
|
||||
&user.CreatedAt,
|
||||
&user.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning user by username: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if roleID.Valid {
|
||||
user.RoleID = uint(roleID.Int64)
|
||||
}
|
||||
if roleName.Valid {
|
||||
user.Role = roleName.String
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// GetUserByID 根据ID获取用户
|
||||
func GetUserByID(id uint) (*models.User, error) {
|
||||
query := `
|
||||
SELECT u.id, u.username, u.email, u.password_hash, u.role_id, COALESCE(r.name, u.role), u.is_active, u.created_at, u.updated_at
|
||||
FROM users u
|
||||
LEFT JOIN roles r ON u.role_id = r.id
|
||||
WHERE u.id = ?
|
||||
`
|
||||
row := config.DB.QueryRow(query, id)
|
||||
|
||||
var user models.User
|
||||
var roleID sql.NullInt64
|
||||
var roleName sql.NullString
|
||||
|
||||
if err := row.Scan(
|
||||
&user.ID,
|
||||
&user.Username,
|
||||
&user.Email,
|
||||
&user.PasswordHash,
|
||||
&roleID,
|
||||
&roleName,
|
||||
&user.IsActive,
|
||||
&user.CreatedAt,
|
||||
&user.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning user by ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if roleID.Valid {
|
||||
user.RoleID = uint(roleID.Int64)
|
||||
}
|
||||
if roleName.Valid {
|
||||
user.Role = roleName.String
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// GetUsers 获取所有用户
|
||||
func GetUsers() ([]models.User, error) {
|
||||
query := `
|
||||
SELECT u.id, u.username, u.email, u.password_hash, u.role_id, COALESCE(r.name, u.role), u.is_active, u.created_at, u.updated_at
|
||||
FROM users u
|
||||
LEFT JOIN roles r ON u.role_id = r.id
|
||||
ORDER BY u.created_at DESC
|
||||
`
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error querying users: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var users []models.User
|
||||
for rows.Next() {
|
||||
var user models.User
|
||||
var roleID sql.NullInt64
|
||||
var roleName sql.NullString
|
||||
|
||||
if err := rows.Scan(
|
||||
&user.ID,
|
||||
&user.Username,
|
||||
&user.Email,
|
||||
&user.PasswordHash,
|
||||
&roleID,
|
||||
&roleName,
|
||||
&user.IsActive,
|
||||
&user.CreatedAt,
|
||||
&user.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning user: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if roleID.Valid {
|
||||
user.RoleID = uint(roleID.Int64)
|
||||
}
|
||||
if roleName.Valid {
|
||||
user.Role = roleName.String
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// CreateUser 创建用户
|
||||
func CreateUser(user *models.User) error {
|
||||
// 如果提供了RoleID,确保它有效。如果没有RoleID但有Role name,尝试查找RoleID
|
||||
if user.RoleID == 0 && user.Role != "" {
|
||||
role, err := GetRoleByName(user.Role)
|
||||
if err == nil && role != nil {
|
||||
user.RoleID = role.ID
|
||||
}
|
||||
}
|
||||
|
||||
query := `
|
||||
INSERT INTO users (username, email, password_hash, role_id, role, is_active, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||
`
|
||||
|
||||
var roleID interface{}
|
||||
if user.RoleID != 0 {
|
||||
roleID = user.RoleID
|
||||
} else {
|
||||
roleID = nil
|
||||
}
|
||||
|
||||
result, err := config.DB.Exec(
|
||||
query,
|
||||
user.Username,
|
||||
user.Email,
|
||||
user.PasswordHash,
|
||||
roleID,
|
||||
user.Role, // Fallback legacy column
|
||||
user.IsActive,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error creating user: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取自增ID
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
log.Printf("Error getting last insert ID: %v", err)
|
||||
return err
|
||||
}
|
||||
user.ID = uint(id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateUser 更新用户
|
||||
func UpdateUser(user *models.User) error {
|
||||
// 同样尝试解析RoleID
|
||||
if user.RoleID == 0 && user.Role != "" {
|
||||
role, err := GetRoleByName(user.Role)
|
||||
if err == nil && role != nil {
|
||||
user.RoleID = role.ID
|
||||
}
|
||||
}
|
||||
|
||||
query := `
|
||||
UPDATE users SET username = ?, email = ?, role_id = ?, role = ?, is_active = ?, updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`
|
||||
|
||||
var roleID interface{}
|
||||
if user.RoleID != 0 {
|
||||
roleID = user.RoleID
|
||||
} else {
|
||||
roleID = nil
|
||||
}
|
||||
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
user.Username,
|
||||
user.Email,
|
||||
roleID,
|
||||
user.Role,
|
||||
user.IsActive,
|
||||
user.ID,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error updating user: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateUserPassword 更新用户密码
|
||||
func UpdateUserPassword(id uint, passwordHash string) error {
|
||||
query := `
|
||||
UPDATE users SET password_hash = ?, updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := config.DB.Exec(query, passwordHash, id)
|
||||
if err != nil {
|
||||
log.Printf("Error updating user password: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteUser 删除用户
|
||||
func DeleteUser(id uint) error {
|
||||
query := "DELETE FROM users WHERE id = ?"
|
||||
_, err := config.DB.Exec(query, id)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting user: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserCount 获取用户总数
|
||||
func GetUserCount() (int, error) {
|
||||
var count int
|
||||
query := "SELECT COUNT(*) FROM users"
|
||||
row := config.DB.QueryRow(query)
|
||||
|
||||
err := row.Scan(&count)
|
||||
if err != nil {
|
||||
log.Printf("Error getting user count: %v", err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// BuildUserResponse 构建用户响应
|
||||
func BuildUserResponse(user *models.User) *models.UserResponse {
|
||||
return &models.UserResponse{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
RoleID: user.RoleID,
|
||||
Role: user.Role,
|
||||
IsActive: user.IsActive,
|
||||
CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: user.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
// BuildUsersResponse 构建用户列表响应
|
||||
func BuildUsersResponse(users []models.User) []models.UserResponse {
|
||||
var responses []models.UserResponse
|
||||
for _, user := range users {
|
||||
responses = append(responses, *BuildUserResponse(&user))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
301
server/repositories/work_repository.go
Normal file
301
server/repositories/work_repository.go
Normal file
@@ -0,0 +1,301 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// GetWorks 获取所有作品
|
||||
func GetWorks() ([]models.Work, error) {
|
||||
query := "SELECT id, title, category, year, hero_img, description, is_featured, created_at, updated_at FROM works"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
log.Printf("Error querying works: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var works []models.Work
|
||||
for rows.Next() {
|
||||
var work models.Work
|
||||
if err := rows.Scan(
|
||||
&work.ID,
|
||||
&work.Title,
|
||||
&work.Category,
|
||||
&work.Year,
|
||||
&work.HeroImg,
|
||||
&work.Description,
|
||||
&work.IsFeatured,
|
||||
&work.CreatedAt,
|
||||
&work.UpdatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning work: %v", err)
|
||||
continue
|
||||
}
|
||||
works = append(works, work)
|
||||
}
|
||||
|
||||
return works, nil
|
||||
}
|
||||
|
||||
// GetWorkByID 根据ID获取作品
|
||||
func GetWorkByID(id string) (*models.Work, error) {
|
||||
query := "SELECT id, title, category, year, hero_img, description, is_featured, created_at, updated_at FROM works WHERE id = ?"
|
||||
row := config.DB.QueryRow(query, id)
|
||||
|
||||
var work models.Work
|
||||
if err := row.Scan(
|
||||
&work.ID,
|
||||
&work.Title,
|
||||
&work.Category,
|
||||
&work.Year,
|
||||
&work.HeroImg,
|
||||
&work.Description,
|
||||
&work.IsFeatured,
|
||||
&work.CreatedAt,
|
||||
&work.UpdatedAt,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.Printf("Error scanning work by ID: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &work, nil
|
||||
}
|
||||
|
||||
// GetWorkTechStack 获取作品的技术栈
|
||||
func GetWorkTechStack(workID string) ([]models.WorkTechStack, error) {
|
||||
query := "SELECT id, work_id, category, item, created_at FROM work_tech_stack WHERE work_id = ?"
|
||||
rows, err := config.DB.Query(query, workID)
|
||||
if err != nil {
|
||||
log.Printf("Error querying work tech stack: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var techStacks []models.WorkTechStack
|
||||
for rows.Next() {
|
||||
var techStack models.WorkTechStack
|
||||
if err := rows.Scan(
|
||||
&techStack.ID,
|
||||
&techStack.WorkID,
|
||||
&techStack.Category,
|
||||
&techStack.Item,
|
||||
&techStack.CreatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning work tech stack: %v", err)
|
||||
continue
|
||||
}
|
||||
techStacks = append(techStacks, techStack)
|
||||
}
|
||||
|
||||
return techStacks, nil
|
||||
}
|
||||
|
||||
// GetWorkGallery 获取作品的图库
|
||||
func GetWorkGallery(workID string) ([]models.WorkGallery, error) {
|
||||
query := "SELECT id, work_id, image_url, sort_order, description, created_at FROM work_gallery WHERE work_id = ? ORDER BY sort_order"
|
||||
rows, err := config.DB.Query(query, workID)
|
||||
if err != nil {
|
||||
log.Printf("Error querying work gallery: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var galleries []models.WorkGallery
|
||||
for rows.Next() {
|
||||
var gallery models.WorkGallery
|
||||
if err := rows.Scan(
|
||||
&gallery.ID,
|
||||
&gallery.WorkID,
|
||||
&gallery.ImageURL,
|
||||
&gallery.SortOrder,
|
||||
&gallery.Description,
|
||||
&gallery.CreatedAt,
|
||||
); err != nil {
|
||||
log.Printf("Error scanning work gallery: %v", err)
|
||||
continue
|
||||
}
|
||||
galleries = append(galleries, gallery)
|
||||
}
|
||||
|
||||
return galleries, nil
|
||||
}
|
||||
|
||||
// BuildWorkResponse 构建作品响应,包含关联数据
|
||||
func BuildWorkResponse(work *models.Work) (*models.WorkResponse, error) {
|
||||
// 获取技术栈
|
||||
techStacks, err := GetWorkTechStack(work.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 按类别分组技术栈
|
||||
techStackMap := make(map[string][]string)
|
||||
for _, ts := range techStacks {
|
||||
techStackMap[ts.Category] = append(techStackMap[ts.Category], ts.Item)
|
||||
}
|
||||
|
||||
// 转换为前端期望的格式
|
||||
var techStackResponse []map[string]interface{}
|
||||
for category, items := range techStackMap {
|
||||
techStackResponse = append(techStackResponse, map[string]interface{}{
|
||||
"category": category,
|
||||
"items": items,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取图库
|
||||
galleries, err := GetWorkGallery(work.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 提取图片URL
|
||||
var galleryImages []string
|
||||
for _, g := range galleries {
|
||||
galleryImages = append(galleryImages, g.ImageURL)
|
||||
}
|
||||
|
||||
// 获取下一个作品ID
|
||||
nextWorkID, err := GetNextWorkID(work.ID)
|
||||
if err != nil {
|
||||
log.Printf("Error getting next work ID: %v", err)
|
||||
nextWorkID = ""
|
||||
}
|
||||
|
||||
return &models.WorkResponse{
|
||||
ID: work.ID,
|
||||
Title: work.Title,
|
||||
Category: work.Category,
|
||||
Year: work.Year,
|
||||
HeroImg: work.HeroImg,
|
||||
Desc: work.Description,
|
||||
TechStack: techStackResponse,
|
||||
Gallery: galleryImages,
|
||||
Links: map[string]interface{}{
|
||||
"live": "#",
|
||||
},
|
||||
Next: nextWorkID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetNextWorkID 获取下一个作品ID(简单实现,实际可能需要更复杂的逻辑)
|
||||
func GetNextWorkID(currentID string) (string, error) {
|
||||
// 获取所有作品ID
|
||||
query := "SELECT id FROM works"
|
||||
rows, err := config.DB.Query(query)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var ids []string
|
||||
for rows.Next() {
|
||||
var id string
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
continue
|
||||
}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
// 找到当前ID的索引
|
||||
index := -1
|
||||
for i, id := range ids {
|
||||
if id == currentID {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没找到或者是最后一个,返回第一个
|
||||
if index == -1 || index == len(ids)-1 {
|
||||
if len(ids) > 0 {
|
||||
return ids[0], nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// 返回下一个
|
||||
return ids[index+1], nil
|
||||
}
|
||||
|
||||
// CreateWork 创建作品
|
||||
func CreateWork(work *models.Work) error {
|
||||
query := `
|
||||
INSERT INTO works (id, title, category, year, hero_img, description, is_featured, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
work.ID,
|
||||
work.Title,
|
||||
work.Category,
|
||||
work.Year,
|
||||
work.HeroImg,
|
||||
work.Description,
|
||||
work.IsFeatured,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error creating work: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateWork 更新作品
|
||||
func UpdateWork(work *models.Work) error {
|
||||
query := `
|
||||
UPDATE works SET title = ?, category = ?, year = ?, hero_img = ?, description = ?, is_featured = ?, updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`
|
||||
_, err := config.DB.Exec(
|
||||
query,
|
||||
work.Title,
|
||||
work.Category,
|
||||
work.Year,
|
||||
work.HeroImg,
|
||||
work.Description,
|
||||
work.IsFeatured,
|
||||
work.ID,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Error updating work: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteWork 删除作品
|
||||
func DeleteWork(id string) error {
|
||||
query := "DELETE FROM works WHERE id = ?"
|
||||
_, err := config.DB.Exec(query, id)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting work: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWorkCount 获取作品总数
|
||||
func GetWorkCount() (int, error) {
|
||||
var count int
|
||||
query := "SELECT COUNT(*) FROM works"
|
||||
row := config.DB.QueryRow(query)
|
||||
|
||||
err := row.Scan(&count)
|
||||
if err != nil {
|
||||
log.Printf("Error getting work count: %v", err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
Reference in New Issue
Block a user