diff --git a/generate/protobuf/permission.proto b/generate/protobuf/permission.proto index 6dd8a65..2a9dec1 100644 --- a/generate/protobuf/permission.proto +++ b/generate/protobuf/permission.proto @@ -252,9 +252,9 @@ message RoleResp { // 定義 PageResponse 用來對應 pager.Response message PageResponse { - int32 page_index = 1; // 頁碼 - int32 page_size = 2; // 每頁顯示數量 - int32 total_pages = 3; // 總頁數 + int64 page_index = 1; // 頁碼 + int64 page_size = 2; // 每頁顯示數量 + int64 total_count = 3; // 總頁數 } // PageRoleResp 對應的 Protobuf message diff --git a/internal/domain/permission.go b/internal/domain/permission.go index 56e152d..c4cac51 100644 --- a/internal/domain/permission.go +++ b/internal/domain/permission.go @@ -39,3 +39,7 @@ const ( PermissionStatusOpenCode PermissionStatus = "open" PermissionStatusCloseCode PermissionStatus = "close" ) + +const ( + AdminRoleID = "GodDog!@#" +) diff --git a/internal/logic/roleservice/get_role_logic.go b/internal/logic/roleservice/get_role_logic.go index 172e854..ad06c8a 100644 --- a/internal/logic/roleservice/get_role_logic.go +++ b/internal/logic/roleservice/get_role_logic.go @@ -1,11 +1,14 @@ package roleservicelogic import ( - "context" - "ark-permission/gen_result/pb/permission" + "ark-permission/internal/domain" + "ark-permission/internal/entity" + "ark-permission/internal/model" "ark-permission/internal/svc" - + ers "code.30cm.net/wanderland/library-go/errors" + "context" + "errors" "github.com/zeromicro/go-zero/core/logx" ) @@ -25,19 +28,164 @@ func NewGetRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRoleLo // GetRole 取得搜尋的角色 func (l *GetRoleLogic) GetRole(in *permission.GetRoleReq) (*permission.GetRoleResp, error) { - // filter := data *Role - // 是否全表搜尋 + // 檢查是否為全表搜尋 if in.GetAll() { - // 不需要帶過濾條件 + return l.getAllRoles() + } + + // 處理分頁參數 + size := int64(20) + if in.GetPageSize() != 0 { + size = in.GetPageSize() + } + index := int64(1) + if in.GetPageIndex() != 0 { + index = in.GetPageIndex() + } + + // 執行角色搜尋和計算總數 + roles, count, err := l.searchRolesWithCount(in, size, index) + if err != nil { + return nil, err + } + + // 組裝結果 + return l.buildRoleResp(roles, in.PageSize, in.PageIndex, count, in.GetPermissions()), nil +} + +// getAllRoles 獲取全表角色 +func (l *GetRoleLogic) getAllRoles() (*permission.GetRoleResp, error) { + // 查詢所有角色 + roles, err := l.svcCtx.RoleRepo.Find(l.ctx) + if err != nil { + return nil, l.handleDBError(err, "failed to get role") + } + + // 計算總數 + count, err := l.svcCtx.RoleRepo.Count(l.ctx, &model.Role{}) + if err != nil { + return nil, l.handleDBError(err, "failed to get role") + } + + // 組裝結果 + return l.buildRoleResp(roles, -1, -1, count, nil), nil +} + +// searchRolesWithCount 搜尋角色並計算總數 +func (l *GetRoleLogic) searchRolesWithCount(in *permission.GetRoleReq, size, index int64) ([]*model.Role, int64, error) { + // 搜尋角色 + roles, err := l.svcCtx.RoleRepo.SearchRoles(l.ctx, &model.Role{ + RoleId: in.GetRoleIds(), + DisplayName: in.GetDisplayName(), + Status: int64(in.GetStatus().Number()), + }, size, index) + if err != nil { + return nil, 0, err + } + + // 計算總數 + count, err := l.svcCtx.RoleRepo.Count(l.ctx, &model.Role{ + RoleId: in.GetRoleIds(), + DisplayName: in.GetDisplayName(), + Status: int64(in.GetStatus().Number()), + }) + if err != nil { + return nil, 0, l.handleDBError(err, "failed to get role") + } + + list := make([]*model.Role, 0, count) + for _, item := range roles { + list = append(list, &item) + } + + return list, count, nil +} + +// handleDBError 處理資料庫錯誤 +func (l *GetRoleLogic) handleDBError(err error, msg string) error { + if errors.Is(model.ErrNotFound, err) { + return ers.ResourceNotFound(msg) + } + return ers.DBError(err.Error()) +} + +// buildRoleResp 組裝角色回應 +func (l *GetRoleLogic) buildRoleResp(roles []*model.Role, pageSize, pageIndex, totalCount int64, filter []string) *permission.GetRoleResp { + list := make([]*permission.RoleResp, 0, len(roles)) + for _, item := range roles { + permissions := make(map[string]string) + // Admin 角色 + if item.RoleId == domain.AdminRoleID { + data, err := l.svcCtx.Permission.FindAllOpenPermission(l.ctx) + if err != nil { + // log + continue + } + + for _, v := range data { + permissions[v.Name] = string(domain.PermissionStatusOpenCode) + } + } else { + rolePermission, err := l.svcCtx.RolePermissionRepo.FindOneByRoleID(l.ctx, item.RoleId) + if err != nil { + // log + continue + } + + var rp = make([]entity.RolePermission, 0, len(rolePermission)) + for _, item := range rolePermission { + rp = append(rp, entity.RolePermission{ + ID: item.Id, + RoleID: item.RoleId.Int64, + PermissionID: item.PermissionId.Int64, + CreateTime: item.CreateTime, + UpdateTime: item.UpdateTime, + }) + + } + + userRolePermission, err := l.svcCtx.PermissionTree.GetRolePermissionTree(rp) + if err != nil { + return nil + } + + if filter == nil { + list = append(list, &permission.RoleResp{ + Id: item.Id, + DisplayName: item.DisplayName, + RoleId: item.RoleId, + Status: permission.PermissionStatus(item.Status), + Permissions: permissions, + CreateTime: item.CreateTime, + UpdateTime: item.UpdateTime, + }) + } else { + for _, p := range filter { + if userRolePermission[p] == domain.PermissionStatusOpenCode { + list = append(list, &permission.RoleResp{ + Id: item.Id, + DisplayName: item.DisplayName, + RoleId: item.RoleId, + Status: permission.PermissionStatus(item.Status), + Permissions: permissions, + CreateTime: item.CreateTime, + UpdateTime: item.UpdateTime, + }) + + break + } + } + } + } } - // RoleIds string `protobuf:"bytes,1,opt,name=role_ids,json=roleIds,proto3" json:"role_ids,omitempty"` - // DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - // Permissions []string `protobuf:"bytes,3,rep,name=permissions,proto3" json:"permissions,omitempty"` - // Status PermissionStatus `protobuf:"varint,4,opt,name=status,proto3,enum=permission.PermissionStatus" json:"status,omitempty"` - // PageIndex int64 `protobuf:"varint,5,opt,name=page_index,json=pageIndex,proto3" json:"page_index,omitempty"` - // PageSize int64 `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - - return &permission.GetRoleResp{}, nil + return &permission.GetRoleResp{ + List: list, + Page: &permission.PageResponse{ + PageSize: pageSize, + PageIndex: pageIndex, + TotalCount: totalCount, + }, + } } diff --git a/internal/model/role_model.go b/internal/model/role_model.go index 44ca443..4ae5d79 100755 --- a/internal/model/role_model.go +++ b/internal/model/role_model.go @@ -2,8 +2,11 @@ package model import ( "context" + "errors" "fmt" + "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" + "strings" "time" ) @@ -25,6 +28,9 @@ type ( session sqlx.Session, roleId string, displayName string) error + Find(ctx context.Context) ([]*Role, error) + Count(ctx context.Context, role *Role) (int64, error) + SearchRoles(ctx context.Context, role *Role, pageIndex, PageSize int64) (result []Role, err error) } customRoleModel struct { @@ -82,3 +88,99 @@ func (m *customRoleModel) TransUpdateStatusByRoleID( _, err := session.ExecCtx(ctx, query, status, updateTime, roleId) return err } + +func (m *defaultRoleModel) Find(ctx context.Context) ([]*Role, error) { + query := fmt.Sprintf("select %s from %s", roleRows, m.table) + var resp []*Role + err := m.conn.QueryRowsCtx(ctx, &resp, query) + switch { + case err == nil: + return resp, nil + case errors.Is(err, sqlc.ErrNotFound): + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultRoleModel) Count(ctx context.Context, role *Role) (int64, error) { + var conditions []string + var args []any + + // 構建條件 + if role.RoleId != "" { + conditions = append(conditions, "`role_id` = ?") + args = append(args, role.RoleId) + } + if role.DisplayName != "" { + conditions = append(conditions, "`display_name` = ?") + args = append(args, role.DisplayName) + } + + if role.Status != 0 { + conditions = append(conditions, "`status` = ?") + args = append(args, role.Status) + } + + // 構建基礎查詢語句 + query := fmt.Sprintf("select COUNT(*) from %s", m.table) + + // 如果有條件,添加 WHERE 子句 + if len(conditions) > 0 { + query += " where " + strings.Join(conditions, " AND ") + } + + var resp int64 + err := m.conn.QueryRowCtx(ctx, &resp, query, args...) + switch { + case err == nil: + return resp, nil + case errors.Is(err, sqlc.ErrNotFound): + return 0, ErrNotFound + default: + return 0, err + } +} + +func (m *customRoleModel) SearchRoles(ctx context.Context, role *Role, pageIndex, PageSize int64) (result []Role, err error) { + var conditions []string + var args []any + + // 構建條件 + if role.RoleId != "" { + conditions = append(conditions, "`role_id` = ?") + args = append(args, role.RoleId) + } + if role.DisplayName != "" { + conditions = append(conditions, "`display_name` = ?") + args = append(args, role.DisplayName) + } + + if role.Status != 0 { + conditions = append(conditions, "`status` = ?") + args = append(args, role.Status) + } + + // 構建基礎查詢語句 + query := fmt.Sprintf("select * from %s", m.table) + + // 如果有條件,添加 WHERE 子句 + if len(conditions) > 0 { + query += " where " + strings.Join(conditions, " AND ") + } + + // 添加排序和分頁 + query += " order by `id` desc limit ? offset ?" + args = append(args, PageSize, (pageIndex-1)*PageSize) + + // 執行查詢 + err = m.conn.QueryRowCtx(ctx, &result, query, args...) + switch { + case err == nil: + return result, nil + case errors.Is(err, sqlc.ErrNotFound): + return nil, ErrNotFound + default: + return nil, err + } +} diff --git a/internal/model/role_permission_model.go b/internal/model/role_permission_model.go index 6d8d94b..c702671 100755 --- a/internal/model/role_permission_model.go +++ b/internal/model/role_permission_model.go @@ -1,6 +1,11 @@ package model -import "github.com/zeromicro/go-zero/core/stores/sqlx" +import ( + "context" + "fmt" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) var _ RolePermissionModel = (*customRolePermissionModel)(nil) @@ -9,6 +14,7 @@ type ( // and implement the added methods in customRolePermissionModel. RolePermissionModel interface { rolePermissionModel + FindOneByRoleID(ctx context.Context, roleID string) ([]*RolePermission, error) } customRolePermissionModel struct { @@ -22,3 +28,17 @@ func NewRolePermissionModel(conn sqlx.SqlConn) RolePermissionModel { defaultRolePermissionModel: newRolePermissionModel(conn), } } + +func (m *customRolePermissionModel) FindOneByRoleID(ctx context.Context, roleID string) ([]*RolePermission, error) { + var resp []*RolePermission + query := fmt.Sprintf("select %s from %s where `role_id` = ?", userRoleRows, m.table) + err := m.conn.QueryRowsCtx(ctx, &resp, query, roleID) + switch err { + case nil: + return resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} diff --git a/internal/model/user_role_model.go b/internal/model/user_role_model.go index 2f89168..8da4374 100755 --- a/internal/model/user_role_model.go +++ b/internal/model/user_role_model.go @@ -1,6 +1,8 @@ package model -import "github.com/zeromicro/go-zero/core/stores/sqlx" +import ( + "github.com/zeromicro/go-zero/core/stores/sqlx" +) var _ UserRoleModel = (*customUserRoleModel)(nil) diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index 1fb63b3..65fdc3c 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -2,8 +2,10 @@ package svc import ( "ark-permission/internal/config" + "ark-permission/internal/domain" "ark-permission/internal/domain/repository" domainUseCase "ark-permission/internal/domain/usecase" + "ark-permission/internal/entity" "ark-permission/internal/lib/required" "ark-permission/internal/model" repo "ark-permission/internal/repository" @@ -22,10 +24,12 @@ type ServiceContext struct { Redis redis.Redis TokenRedisRepo repository.TokenRepository PolicyAgent domainUseCase.OpaUseCase + PermissionTree usecase.PermissionTree - Conn sqlx.SqlConn - Permission model.PermissionModel - RoleRepo model.RoleModel + Conn sqlx.SqlConn + Permission model.PermissionModel + RoleRepo model.RoleModel + RolePermissionRepo model.RolePermissionModel } func NewServiceContext(c config.Config) *ServiceContext { @@ -47,6 +51,30 @@ func NewServiceContext(c config.Config) *ServiceContext { panic(err) } + t := usecase.NewPermissionTree() + pm := model.NewPermissionModel(sqlConn) + permission, err := pm.FindAllOpenPermission(context.Background()) + if err != nil { + panic(err) + } + + for _, item := range permission { + err := t.AddPermission(item.Id, entity.Permission{ + ID: item.Id, + Parent: item.Parent.Int64, + Name: item.Name, + HTTPPath: item.HttpPath, + HTTPMethod: item.HttpMethod, + + Status: int(item.Status), + Type: domain.PermissionType(item.Type), + CreateTime: item.CreateTime, + UpdateTime: item.UpdateTime, + }) + if err != nil { + continue + } + } return &ServiceContext{ Config: c, Validate: required.MustValidator(), @@ -54,10 +82,11 @@ func NewServiceContext(c config.Config) *ServiceContext { TokenRedisRepo: repo.NewTokenRepository(repo.TokenRepositoryParam{ Store: newRedis, }), - PolicyAgent: pa, - - Permission: model.NewPermissionModel(sqlConn), - RoleRepo: model.NewRoleModel(sqlConn), - Conn: sqlConn, + PolicyAgent: pa, + PermissionTree: *t, + Permission: pm, + RoleRepo: model.NewRoleModel(sqlConn), + RolePermissionRepo: model.NewRolePermissionModel(sqlConn), + Conn: sqlConn, } }