Files
silk/server-go/internal/handler/organization.go
T
2026-08-17 21:43:26 +08:00

202 lines
6.5 KiB
Go

package handler
import (
"net/http"
"strings"
"time"
"silk-server-go/internal/middleware"
"silk-server-go/internal/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// RegisterOrganizationRoutes 注册组织和成员数据范围路由。
func RegisterOrganizationRoutes(rg *gin.RouterGroup, db *gorm.DB) {
perm := middleware.RequirePermission(db, "organization:manage")
rg.GET("/organizations", perm, listOrganizations(db))
rg.POST("/organizations", perm, createOrganization(db))
rg.PATCH("/organizations/:id", perm, updateOrganization(db))
rg.GET("/organizations/:id/members", perm, listOrganizationMembers(db))
rg.POST("/organizations/:id/members", perm, addOrganizationMember(db))
rg.DELETE("/organizations/:id/members/:userId", perm, removeOrganizationMember(db))
}
func listOrganizations(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
q := db.Model(&model.Organization{})
if !hasGlobalAccess(c) {
q = applyOrgScope(q, c, "organizations.id")
}
var list []model.Organization
q.Order("created_at DESC").Find(&list)
c.JSON(http.StatusOK, list)
}
}
func createOrganization(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
var body struct {
Name string `json:"name"`
Code string `json:"code"`
Description *string `json:"description"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if strings.TrimSpace(body.Name) == "" || strings.TrimSpace(body.Code) == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "组织名称和编码不能为空"})
return
}
var count int64
db.Model(&model.Organization{}).Where("code = ?", body.Code).Count(&count)
if count > 0 {
c.JSON(http.StatusConflict, gin.H{"error": "组织编码已存在"})
return
}
org := model.Organization{Name: body.Name, Code: body.Code, Description: body.Description, Status: "active"}
if err := db.Create(&org).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "创建组织失败"})
return
}
c.JSON(http.StatusCreated, org)
}
}
func updateOrganization(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
id := c.Param("id")
var org model.Organization
if db.Where("id = ?", id).First(&org).Error != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "organization not found"})
return
}
if !canAccessOrganization(db, c, id) {
c.JSON(http.StatusForbidden, gin.H{"error": "无权管理该组织"})
return
}
updates, err := bindUpdates(c)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if len(updates) > 0 {
if err := db.Model(&model.Organization{}).Where("id = ?", id).Updates(updates).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "更新组织失败"})
return
}
}
db.Where("id = ?", id).First(&org)
c.JSON(http.StatusOK, org)
}
}
func addOrganizationMember(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
orgID := c.Param("id")
var org model.Organization
if db.Where("id = ?", orgID).First(&org).Error != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "organization not found"})
return
}
if !canAccessOrganization(db, c, orgID) {
c.JSON(http.StatusForbidden, gin.H{"error": "无权管理该组织"})
return
}
var body struct {
UserID string `json:"userId"`
Role string `json:"role"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if !isUUID(body.UserID) {
c.JSON(http.StatusBadRequest, gin.H{"error": "userId 不是合法的 UUID"})
return
}
var user model.User
if db.Where("id = ?", body.UserID).First(&user).Error != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
role := body.Role
if role == "" {
role = "member"
}
if role != "member" && role != "admin" {
c.JSON(http.StatusBadRequest, gin.H{"error": "组织角色仅支持 member/admin"})
return
}
var count int64
db.Model(&model.OrganizationMember{}).
Where("organization_id = ? AND user_id = ?", orgID, body.UserID).
Count(&count)
if count > 0 {
c.JSON(http.StatusConflict, gin.H{"error": "用户已在该组织"})
return
}
member := model.OrganizationMember{OrganizationID: orgID, UserID: body.UserID, Role: role}
if err := db.Create(&member).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "添加成员失败"})
return
}
c.JSON(http.StatusCreated, member)
}
}
func listOrganizationMembers(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
orgID := c.Param("id")
var org model.Organization
if db.Where("id = ?", orgID).First(&org).Error != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "organization not found"})
return
}
if !canAccessOrganization(db, c, orgID) {
c.JSON(http.StatusForbidden, gin.H{"error": "无权查看该组织成员"})
return
}
var rows []struct {
ID string `gorm:"column:id" json:"id"`
OrganizationID string `gorm:"column:organization_id" json:"organizationId"`
UserID string `gorm:"column:user_id" json:"userId"`
Role string `gorm:"column:role" json:"role"`
CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
Username string `gorm:"column:username" json:"username"`
Email string `gorm:"column:email" json:"email"`
FullName *string `gorm:"column:full_name" json:"fullName,omitempty"`
}
if err := db.Table("organization_members om").
Select("om.id, om.organization_id, om.user_id, om.role, om.created_at, u.username, u.email, u.full_name").
Joins("JOIN users u ON u.id = om.user_id").
Where("om.organization_id = ?", orgID).
Order("om.created_at DESC").
Scan(&rows).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "查询组织成员失败"})
return
}
c.JSON(http.StatusOK, rows)
}
}
func removeOrganizationMember(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
orgID := c.Param("id")
userID := c.Param("userId")
var member model.OrganizationMember
if db.Where("organization_id = ? AND user_id = ?", orgID, userID).First(&member).Error != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "organization member not found"})
return
}
if !canAccessOrganization(db, c, orgID) {
c.JSON(http.StatusForbidden, gin.H{"error": "无权管理该组织"})
return
}
db.Where("id = ?", member.ID).Delete(&model.OrganizationMember{})
c.JSON(http.StatusOK, gin.H{"organizationId": orgID, "userId": userID})
}
}