作者 yangfu

增加 rbac 服务

@@ -2,6 +2,7 @@ package factory @@ -2,6 +2,7 @@ package factory
2 2
3 import ( 3 import (
4 "github.com/linmadan/egglib-go/transaction/pg" 4 "github.com/linmadan/egglib-go/transaction/pg"
  5 + "github.com/tiptok/godevp/pkg/domain"
5 "github.com/tiptok/godevp/pkg/domain/role" 6 "github.com/tiptok/godevp/pkg/domain/role"
6 "github.com/tiptok/godevp/pkg/domain/users" 7 "github.com/tiptok/godevp/pkg/domain/users"
7 "github.com/tiptok/godevp/pkg/infrastructure/repository" 8 "github.com/tiptok/godevp/pkg/infrastructure/repository"
@@ -22,3 +23,19 @@ func CreateRoleRepository(options map[string]interface{}) (role.RoleRepository, @@ -22,3 +23,19 @@ func CreateRoleRepository(options map[string]interface{}) (role.RoleRepository,
22 } 23 }
23 return repository.NewRoleRepository(transactionContext) 24 return repository.NewRoleRepository(transactionContext)
24 } 25 }
  26 +
  27 +func CreateAccessRepository(options map[string]interface{}) (domain.AccessRepository, error) {
  28 + var transactionContext *pg.TransactionContext
  29 + if value, ok := options["transactionContext"]; ok {
  30 + transactionContext = value.(*pg.TransactionContext)
  31 + }
  32 + return repository.NewAccessRepository(transactionContext)
  33 +}
  34 +
  35 +func CreateRoleAccessRepository(options map[string]interface{}) (domain.RoleAccessRepository, error) {
  36 + var transactionContext *pg.TransactionContext
  37 + if value, ok := options["transactionContext"]; ok {
  38 + transactionContext = value.(*pg.TransactionContext)
  39 + }
  40 + return repository.NewRoleAccessRepository(transactionContext)
  41 +}
  1 +package command
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type SetRoleAccessCommand struct {
  10 + // 角色id
  11 + RoleId int64 `json:"roleId,omitempty"`
  12 + // 权限编号列表
  13 + AccessIds []int64 `json:"accessIds,omitempty"`
  14 +}
  15 +
  16 +func (setRoleAccessCommand *SetRoleAccessCommand) Valid(validation *validation.Validation) {
  17 + validation.SetError("CustomValid", "未实现的自定义认证")
  18 +}
  19 +
  20 +func (setRoleAccessCommand *SetRoleAccessCommand) ValidateCommand() error {
  21 + valid := validation.Validation{}
  22 + b, err := valid.Valid(setRoleAccessCommand)
  23 + if err != nil {
  24 + return err
  25 + }
  26 + if !b {
  27 + for _, validErr := range valid.Errors {
  28 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  29 + }
  30 + }
  31 + return nil
  32 +}
  1 +package query
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type AccessQuery struct {
  10 +}
  11 +
  12 +func (accessQuery *AccessQuery) Valid(validation *validation.Validation) {
  13 + validation.SetError("CustomValid", "未实现的自定义认证")
  14 +}
  15 +
  16 +func (accessQuery *AccessQuery) ValidateQuery() error {
  17 + valid := validation.Validation{}
  18 + b, err := valid.Valid(accessQuery)
  19 + if err != nil {
  20 + return err
  21 + }
  22 + if !b {
  23 + for _, validErr := range valid.Errors {
  24 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  25 + }
  26 + }
  27 + return nil
  28 +}
  1 +package query
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type RoleAccessQuery struct {
  10 + // 角色id
  11 + RoleId int64 `json:"roleId" valid:"Required"`
  12 +}
  13 +
  14 +func (roleAccessQuery *RoleAccessQuery) Valid(validation *validation.Validation) {
  15 + validation.SetError("CustomValid", "未实现的自定义认证")
  16 +}
  17 +
  18 +func (roleAccessQuery *RoleAccessQuery) ValidateQuery() error {
  19 + valid := validation.Validation{}
  20 + b, err := valid.Valid(roleAccessQuery)
  21 + if err != nil {
  22 + return err
  23 + }
  24 + if !b {
  25 + for _, validErr := range valid.Errors {
  26 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  27 + }
  28 + }
  29 + return nil
  30 +}
  1 +package service
  2 +
  3 +import (
  4 + "github.com/linmadan/egglib-go/core/application"
  5 + "github.com/linmadan/egglib-go/transaction/pg"
  6 + "github.com/tiptok/godevp/pkg/application/factory"
  7 + "github.com/tiptok/godevp/pkg/application/rbac/command"
  8 + "github.com/tiptok/godevp/pkg/application/rbac/query"
  9 + "github.com/tiptok/godevp/pkg/domain"
  10 + role2 "github.com/tiptok/godevp/pkg/domain/role"
  11 + "github.com/tiptok/godevp/pkg/infrastructure/dao"
  12 +)
  13 +
  14 +// 权限服务
  15 +type RbacService struct {
  16 +}
  17 +
  18 +// 获取菜单列表
  19 +func (rbacService *RbacService) Access(accessQuery *query.AccessQuery) (interface{}, error) {
  20 + if err := accessQuery.ValidateQuery(); err != nil {
  21 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  22 + }
  23 + transactionContext, err := factory.CreateTransactionContext(nil)
  24 + if err != nil {
  25 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  26 + }
  27 + if err := transactionContext.StartTransaction(); err != nil {
  28 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  29 + }
  30 + defer func() {
  31 + transactionContext.RollbackTransaction()
  32 + }()
  33 +
  34 + var AccessRepository, _ = factory.CreateAccessRepository(map[string]interface{}{"transactionContext": transactionContext})
  35 + var access []*domain.Access
  36 + if _, access, err = AccessRepository.Find(map[string]interface{}{"sortByParentId": "ASC", "sortBySort": "ASC"}); err != nil {
  37 + return nil, err
  38 + }
  39 + var rspList []interface{}
  40 + for _, item := range access {
  41 + rspList = append(rspList, map[string]interface{}{
  42 + "id": item.Id,
  43 + "name": item.AccessName,
  44 + "icon": "",
  45 + "parentId": item.ParentId,
  46 + "sort": item.Sort,
  47 + "code": item.AccessCode,
  48 + })
  49 + }
  50 + rsp := map[string]interface{}{
  51 + "lists": rspList,
  52 + }
  53 +
  54 + if err := transactionContext.CommitTransaction(); err != nil {
  55 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  56 + }
  57 + return rsp, nil
  58 +}
  59 +
  60 +// 角色权限
  61 +func (rbacService *RbacService) RoleAccess(roleAccessQuery *query.RoleAccessQuery) (interface{}, error) {
  62 + if err := roleAccessQuery.ValidateQuery(); err != nil {
  63 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  64 + }
  65 + transactionContext, err := factory.CreateTransactionContext(nil)
  66 + if err != nil {
  67 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  68 + }
  69 + if err := transactionContext.StartTransaction(); err != nil {
  70 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  71 + }
  72 + defer func() {
  73 + transactionContext.RollbackTransaction()
  74 + }()
  75 +
  76 + RoleAccessDao, _ := dao.NewRoleAccessDao(transactionContext.(*pg.TransactionContext))
  77 + RoleRepository, _ := factory.CreateRoleRepository(map[string]interface{}{"transactionContext": transactionContext})
  78 + var role *role2.Role
  79 +
  80 + if role, err = RoleRepository.FindOne(map[string]interface{}{"id": roleAccessQuery.RoleId}); err != nil {
  81 + return nil, application.ThrowError(application.TRANSACTION_ERROR, "角色不存在")
  82 + }
  83 + accessIds, _ := RoleAccessDao.GetRoleAccess(roleAccessQuery.RoleId)
  84 + rsp := map[string]interface{}{
  85 + "roleId": role.Id,
  86 + "roleName": role.RoleName,
  87 + "accessIds": accessIds,
  88 + }
  89 +
  90 + if err := transactionContext.CommitTransaction(); err != nil {
  91 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  92 + }
  93 + return rsp, nil
  94 +}
  95 +
  96 +// 设置角色权限
  97 +func (rbacService *RbacService) SetRoleAccess(setRoleAccessCommand *command.SetRoleAccessCommand) (interface{}, error) {
  98 + if err := setRoleAccessCommand.ValidateCommand(); err != nil {
  99 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  100 + }
  101 + transactionContext, err := factory.CreateTransactionContext(nil)
  102 + if err != nil {
  103 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  104 + }
  105 + if err := transactionContext.StartTransaction(); err != nil {
  106 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  107 + }
  108 + defer func() {
  109 + transactionContext.RollbackTransaction()
  110 + }()
  111 +
  112 + AccessRepository, _ := factory.CreateAccessRepository(map[string]interface{}{"transactionContext": transactionContext})
  113 + RoleRepository, _ := factory.CreateRoleRepository(map[string]interface{}{"transactionContext": transactionContext})
  114 + RoleAccessDao, _ := dao.NewRoleAccessDao(transactionContext.(*pg.TransactionContext))
  115 +
  116 + if _, err = RoleRepository.FindOne(map[string]interface{}{"id": setRoleAccessCommand.RoleId}); err != nil {
  117 + return nil, application.ThrowError(application.RES_NO_FIND_ERROR, "角色不存在")
  118 + }
  119 +
  120 + var accessMap = make(map[int64]*domain.Access)
  121 + _, access, _ := AccessRepository.Find(map[string]interface{}{"inAccessIds": setRoleAccessCommand.AccessIds})
  122 + for _, v := range access {
  123 + accessMap[v.Id] = v
  124 + }
  125 +
  126 + if err = RoleAccessDao.DeleteRoleAccess(setRoleAccessCommand.RoleId); err != nil {
  127 + return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
  128 + }
  129 + if len(setRoleAccessCommand.AccessIds) > 0 {
  130 + var roleAccess []*domain.RoleAccess
  131 + for _, v := range setRoleAccessCommand.AccessIds {
  132 + item := &domain.RoleAccess{
  133 + RoleId: setRoleAccessCommand.RoleId,
  134 + AccessId: v,
  135 + }
  136 + if accessItem, ok := accessMap[v]; ok {
  137 + item.Object = accessItem.Object
  138 + item.Action = accessItem.Action
  139 + item.Option = accessItem.AccessCode
  140 + }
  141 + roleAccess = append(roleAccess, item)
  142 + }
  143 + if err = RoleAccessDao.SaveRoleAccess(roleAccess); err != nil {
  144 + return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
  145 + }
  146 + }
  147 +
  148 + if err := transactionContext.CommitTransaction(); err != nil {
  149 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  150 + }
  151 + return nil, nil
  152 +}
  153 +
  154 +func NewRbacService(options map[string]interface{}) *RbacService {
  155 + newRbacService := &RbacService{}
  156 + return newRbacService
  157 +}
  1 +package domain
  2 +
  3 +// 权限
  4 +type Access struct {
  5 + // dcc
  6 + Id int64 `json:"id"`
  7 + // 父级Id
  8 + ParentId int64 `json:"parentId"`
  9 + // 权限名称
  10 + AccessName string `json:"accessName"`
  11 + // 权限名称
  12 + AccessCode string `json:"accessCode"`
  13 + // 权限类型 menu button data
  14 + AccessType string `json:"accessType"`
  15 + // 排序
  16 + Sort int `json:"sort"`
  17 + // 请求对象 接口地址/对象
  18 + Object string `json:"object"`
  19 + // 操作方法 httpMethod/read/write
  20 + Action string `json:"action"`
  21 + // 所属功能模块
  22 + Module string `json:"module"`
  23 + // 图标
  24 + Icon string `json:"icon"`
  25 + // 状态 1-启用 0-禁用
  26 + Status int `json:"status"`
  27 +}
  28 +
  29 +type AccessRepository interface {
  30 + Save(access *Access) (*Access, error)
  31 + Remove(access *Access) (*Access, error)
  32 + FindOne(queryOptions map[string]interface{}) (*Access, error)
  33 + Find(queryOptions map[string]interface{}) (int64, []*Access, error)
  34 +}
  35 +
  36 +func (access *Access) Identify() interface{} {
  37 + if access.Id == 0 {
  38 + return nil
  39 + }
  40 + return access.Id
  41 +}
  42 +
  43 +func (access *Access) Update(data map[string]interface{}) error {
  44 + if ParentId, ok := data["ParentId"]; ok {
  45 + access.ParentId = ParentId.(int64)
  46 + }
  47 + if AccessName, ok := data["AccessName"]; ok {
  48 + access.AccessName = AccessName.(string)
  49 + }
  50 + if AccessCode, ok := data["AccessCode"]; ok {
  51 + access.AccessCode = AccessCode.(string)
  52 + }
  53 + if AccessType, ok := data["AccessType"]; ok {
  54 + access.AccessType = AccessType.(string)
  55 + }
  56 + if Sort, ok := data["Sort"]; ok {
  57 + access.Sort = Sort.(int)
  58 + }
  59 + if Object, ok := data["Object"]; ok {
  60 + access.Object = Object.(string)
  61 + }
  62 + if Action, ok := data["Action"]; ok {
  63 + access.Action = Action.(string)
  64 + }
  65 + if Module, ok := data["Module"]; ok {
  66 + access.Module = Module.(string)
  67 + }
  68 + if Icon, ok := data["Icon"]; ok {
  69 + access.Icon = Icon.(string)
  70 + }
  71 + if Status, ok := data["Status"]; ok {
  72 + access.Status = Status.(int)
  73 + }
  74 + return nil
  75 +}
  1 +package domain
  2 +
  3 +// 角色权限
  4 +type RoleAccess struct {
  5 + // dcc
  6 + Id int64 `json:"id"`
  7 + // 角色id
  8 + RoleId int64 `json:"roleId"`
  9 + // 权限编号
  10 + AccessId int64 `json:"accessId"`
  11 + // 请求对象 接口地址/对象
  12 + Object string `json:"object"`
  13 + // 操作方法 httpMethod/read/write
  14 + Action string `json:"action"`
  15 + // 可选对象
  16 + Option string `json:"option"`
  17 +}
  18 +
  19 +type RoleAccessRepository interface {
  20 + Save(roleAccess *RoleAccess) (*RoleAccess, error)
  21 + Remove(roleAccess *RoleAccess) (*RoleAccess, error)
  22 + FindOne(queryOptions map[string]interface{}) (*RoleAccess, error)
  23 + Find(queryOptions map[string]interface{}) (int64, []*RoleAccess, error)
  24 +}
  25 +
  26 +func (roleAccess *RoleAccess) Identify() interface{} {
  27 + if roleAccess.Id == 0 {
  28 + return nil
  29 + }
  30 + return roleAccess.Id
  31 +}
  32 +
  33 +func (roleAccess *RoleAccess) Update(data map[string]interface{}) error {
  34 + if RoleId, ok := data["RoleId"]; ok {
  35 + roleAccess.RoleId = RoleId.(int64)
  36 + }
  37 + if AccessId, ok := data["AccessId"]; ok {
  38 + roleAccess.AccessId = AccessId.(int64)
  39 + }
  40 + if Object, ok := data["Object"]; ok {
  41 + roleAccess.Object = Object.(string)
  42 + }
  43 + if Action, ok := data["Action"]; ok {
  44 + roleAccess.Action = Action.(string)
  45 + }
  46 + if Option, ok := data["Option"]; ok {
  47 + roleAccess.Option = Option.(string)
  48 + }
  49 + return nil
  50 +}
  1 +package dao
  2 +
  3 +import (
  4 + "fmt"
  5 + "github.com/go-pg/pg/v10"
  6 + pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
  7 + "github.com/tiptok/gocomm/common"
  8 + "github.com/tiptok/godevp/pkg/domain"
  9 + "github.com/tiptok/godevp/pkg/infrastructure/pg/models"
  10 +)
  11 +
  12 +type RoleAccessDao struct {
  13 + transactionContext *pgTransaction.TransactionContext
  14 +}
  15 +
  16 +func (dao *RoleAccessDao) DeleteRoleAccess(roleId int64) error {
  17 + tx := dao.transactionContext.PgTx
  18 + q := tx.Model(new(models.RoleAccess))
  19 + q.Where("role_id=?", roleId)
  20 + _, err := q.Delete()
  21 + return err
  22 +}
  23 +
  24 +func (dao *RoleAccessDao) GetRoleAccess(roleId ...int64) ([]int64, error) {
  25 + if len(roleId) == 0 {
  26 + return []int64{}, nil
  27 + }
  28 + tx := dao.transactionContext.PgDd
  29 + q := tx.Model(new(models.RoleAccess))
  30 + q.Column("access_id")
  31 + if len(roleId) == 1 {
  32 + q.Where("role_id=?", roleId[0])
  33 + } else {
  34 + q.Where("role_id in (?)", pg.In(roleId))
  35 + }
  36 + var accessIds []int64
  37 + err := q.Distinct().Select(&accessIds)
  38 + return accessIds, err
  39 +}
  40 +
  41 +func (dao *RoleAccessDao) SaveRoleAccess(roleAccess []*domain.RoleAccess) error {
  42 + if len(roleAccess) == 0 {
  43 + return nil
  44 + }
  45 + tx := dao.transactionContext.PgTx
  46 + var modelsRoleAccess []*models.RoleAccess
  47 + for i := range roleAccess {
  48 + var item *models.RoleAccess
  49 + common.GobModelTransform(&item, roleAccess[i])
  50 + if item == nil {
  51 + continue
  52 + }
  53 + modelsRoleAccess = append(modelsRoleAccess, item)
  54 + }
  55 + _, err := tx.Model(&modelsRoleAccess).Insert()
  56 + return err
  57 +}
  58 +
  59 +func NewRoleAccessDao(transactionContext *pgTransaction.TransactionContext) (*RoleAccessDao, error) {
  60 + if transactionContext == nil {
  61 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  62 + } else {
  63 + return &RoleAccessDao{
  64 + transactionContext: transactionContext,
  65 + }, nil
  66 + }
  67 +}
  1 +package models
  2 +
  3 +type Access struct {
  4 + TableName string `pg:"access,alias:access"`
  5 + // dcc
  6 + Id int64
  7 + // 父级Id
  8 + ParentId int64
  9 + // 权限名称
  10 + AccessName string
  11 + // 权限名称
  12 + AccessCode string
  13 + // 权限类型 menu button data
  14 + AccessType string
  15 + // 排序
  16 + Sort int
  17 + // 请求对象 接口地址/对象
  18 + Object string
  19 + // 操作方法 httpMethod/read/write
  20 + Action string
  21 + // 所属功能模块
  22 + Module string
  23 + // 图标
  24 + Icon string
  25 + // 状态 1-启用 0-禁用
  26 + Status int
  27 +}
  1 +package models
  2 +
  3 +type RoleAccess struct {
  4 + TableName string `pg:"role_access,alias:role_access"`
  5 + // dcc
  6 + Id int64
  7 + // 角色id
  8 + RoleId int64
  9 + // 权限编号
  10 + AccessId int64
  11 + // 请求对象 接口地址/对象
  12 + Object string
  13 + // 操作方法 httpMethod/read/write
  14 + Action string
  15 + // 可选对象
  16 + Option string
  17 +}
  1 +package repository
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/go-pg/pg/v10"
  7 + pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
  8 + "github.com/tiptok/godevp/pkg/domain"
  9 + "github.com/tiptok/godevp/pkg/infrastructure/pg/models"
  10 +)
  11 +
  12 +type AccessRepository struct {
  13 + transactionContext *pgTransaction.TransactionContext
  14 +}
  15 +
  16 +func (repository *AccessRepository) nextIdentify() (int64, error) {
  17 + return 0, nil
  18 +}
  19 +func (repository *AccessRepository) Save(access *domain.Access) (*domain.Access, error) {
  20 + tx := repository.transactionContext.PgTx
  21 + if access.Identify() == nil {
  22 + _, err := repository.nextIdentify()
  23 + if err != nil {
  24 + return access, err
  25 + }
  26 + if _, err := tx.QueryOne(
  27 + pg.Scan(&access.Id, &access.ParentId, &access.AccessName, &access.AccessCode, &access.AccessType, &access.Sort, &access.Object, &access.Action, &access.Module, &access.Icon, &access.Status),
  28 + "INSERT INTO access (id, parent_id, access_name, access_code, access_type, sort, object, action, module, icon, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING id, parent_id, access_name, access_code, access_type, sort, object, action, module, icon, status",
  29 + access.Id, access.ParentId, access.AccessName, access.AccessCode, access.AccessType, access.Sort, access.Object, access.Action, access.Module, access.Icon, access.Status); err != nil {
  30 + return access, err
  31 + }
  32 + } else {
  33 + if _, err := tx.QueryOne(
  34 + pg.Scan(&access.Id, &access.ParentId, &access.AccessName, &access.AccessCode, &access.AccessType, &access.Sort, &access.Object, &access.Action, &access.Module, &access.Icon, &access.Status),
  35 + "UPDATE access SET id=?, parent_id=?, access_name=?, access_code=?, access_type=?, sort=?, object=?, action=?, module=?, icon=?, status=? WHERE id=? RETURNING id, parent_id, access_name, access_code, access_type, sort, object, action, module, icon, status",
  36 + access.Id, access.ParentId, access.AccessName, access.AccessCode, access.AccessType, access.Sort, access.Object, access.Action, access.Module, access.Icon, access.Status, access.Identify()); err != nil {
  37 + return access, err
  38 + }
  39 + }
  40 + return access, nil
  41 +}
  42 +func (repository *AccessRepository) Remove(access *domain.Access) (*domain.Access, error) {
  43 + tx := repository.transactionContext.PgTx
  44 + accessModel := new(models.Access)
  45 + accessModel.Id = access.Identify().(int64)
  46 + if _, err := tx.Model(accessModel).WherePK().Delete(); err != nil {
  47 + return access, err
  48 + }
  49 + return access, nil
  50 +}
  51 +func (repository *AccessRepository) FindOne(queryOptions map[string]interface{}) (*domain.Access, error) {
  52 + tx := repository.transactionContext.PgTx
  53 + accessModel := new(models.Access)
  54 + query := tx.Model(accessModel)
  55 + if accessId, ok := queryOptions["id"]; ok {
  56 + query = query.Where("access.id = ?", accessId)
  57 + }
  58 + if err := query.First(); err != nil {
  59 + if err.Error() == "pg: no rows in result set" {
  60 + return nil, fmt.Errorf("没有此资源")
  61 + } else {
  62 + return nil, err
  63 + }
  64 + }
  65 + if accessModel.Id == 0 {
  66 + return nil, nil
  67 + } else {
  68 + return repository.transformPgModelToDomainModel(accessModel)
  69 + }
  70 +}
  71 +func (repository *AccessRepository) Find(queryOptions map[string]interface{}) (int64, []*domain.Access, error) {
  72 + tx := repository.transactionContext.PgTx
  73 + var accessModels []*models.Access
  74 + accesss := make([]*domain.Access, 0)
  75 + query := tx.Model(&accessModels)
  76 + if offset, ok := queryOptions["offset"]; ok {
  77 + offset := offset.(int)
  78 + if offset > -1 {
  79 + query = query.Offset(offset)
  80 + }
  81 + } else {
  82 + query = query.Offset(0)
  83 + }
  84 + if limit, ok := queryOptions["limit"]; ok {
  85 + limit := limit.(int)
  86 + if limit > -1 {
  87 + query = query.Limit(limit)
  88 + }
  89 + } else {
  90 + query = query.Limit(20)
  91 + }
  92 + if inAccessIds, ok := queryOptions["inAccessIds"]; ok {
  93 + query.Where("id in (?)", pg.In(inAccessIds))
  94 + }
  95 +
  96 + if sortByParentId, ok := queryOptions["sortByParentId"]; ok {
  97 + query.Order(fmt.Sprintf("%v %v", "parent_id", sortByParentId))
  98 + }
  99 + if sortBySort, ok := queryOptions["sortBySort"]; ok {
  100 + query.Order(fmt.Sprintf("%v %v", "sort", sortBySort))
  101 + }
  102 + if count, err := query.Order("id DESC").SelectAndCount(); err != nil {
  103 + return 0, accesss, err
  104 + } else {
  105 + for _, accessModel := range accessModels {
  106 + if access, err := repository.transformPgModelToDomainModel(accessModel); err != nil {
  107 + return 0, accesss, err
  108 + } else {
  109 + accesss = append(accesss, access)
  110 + }
  111 + }
  112 + return int64(count), accesss, nil
  113 + }
  114 +}
  115 +func (repository *AccessRepository) transformPgModelToDomainModel(accessModel *models.Access) (*domain.Access, error) {
  116 + return &domain.Access{
  117 + Id: accessModel.Id,
  118 + ParentId: accessModel.ParentId,
  119 + AccessName: accessModel.AccessName,
  120 + AccessCode: accessModel.AccessCode,
  121 + AccessType: accessModel.AccessType,
  122 + Sort: accessModel.Sort,
  123 + Object: accessModel.Object,
  124 + Action: accessModel.Action,
  125 + Module: accessModel.Module,
  126 + Icon: accessModel.Icon,
  127 + Status: accessModel.Status,
  128 + }, nil
  129 +}
  130 +func NewAccessRepository(transactionContext *pgTransaction.TransactionContext) (*AccessRepository, error) {
  131 + if transactionContext == nil {
  132 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  133 + } else {
  134 + return &AccessRepository{
  135 + transactionContext: transactionContext,
  136 + }, nil
  137 + }
  138 +}
  1 +package repository
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/go-pg/pg/v10"
  7 + pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
  8 + "github.com/tiptok/godevp/pkg/domain"
  9 + "github.com/tiptok/godevp/pkg/infrastructure/pg/models"
  10 +)
  11 +
  12 +type RoleAccessRepository struct {
  13 + transactionContext *pgTransaction.TransactionContext
  14 +}
  15 +
  16 +func (repository *RoleAccessRepository) nextIdentify() (int64, error) {
  17 + return 0, nil
  18 +}
  19 +func (repository *RoleAccessRepository) Save(roleAccess *domain.RoleAccess) (*domain.RoleAccess, error) {
  20 + tx := repository.transactionContext.PgTx
  21 + if roleAccess.Identify() == nil {
  22 + _, err := repository.nextIdentify()
  23 + if err != nil {
  24 + return roleAccess, err
  25 + }
  26 + if _, err := tx.QueryOne(
  27 + pg.Scan(&roleAccess.Id, &roleAccess.RoleId, &roleAccess.AccessId, &roleAccess.Object, &roleAccess.Action, &roleAccess.Option),
  28 + "INSERT INTO role_access (id, role_id, access_id, object, action, option) VALUES (?, ?, ?, ?, ?, ?) RETURNING id, role_id, access_id, object, action, option",
  29 + roleAccess.Id, roleAccess.RoleId, roleAccess.AccessId, roleAccess.Object, roleAccess.Action, roleAccess.Option); err != nil {
  30 + return roleAccess, err
  31 + }
  32 + } else {
  33 + if _, err := tx.QueryOne(
  34 + pg.Scan(&roleAccess.Id, &roleAccess.RoleId, &roleAccess.AccessId, &roleAccess.Object, &roleAccess.Action, &roleAccess.Option),
  35 + "UPDATE role_access SET id=?, role_id=?, access_id=?, object=?, action=?, option=? WHERE id=? RETURNING id, role_id, access_id, object, action, option",
  36 + roleAccess.Id, roleAccess.RoleId, roleAccess.AccessId, roleAccess.Object, roleAccess.Action, roleAccess.Option, roleAccess.Identify()); err != nil {
  37 + return roleAccess, err
  38 + }
  39 + }
  40 + return roleAccess, nil
  41 +}
  42 +func (repository *RoleAccessRepository) Remove(roleAccess *domain.RoleAccess) (*domain.RoleAccess, error) {
  43 + tx := repository.transactionContext.PgTx
  44 + roleAccessModel := new(models.RoleAccess)
  45 + roleAccessModel.Id = roleAccess.Identify().(int64)
  46 + if _, err := tx.Model(roleAccessModel).WherePK().Delete(); err != nil {
  47 + return roleAccess, err
  48 + }
  49 + return roleAccess, nil
  50 +}
  51 +func (repository *RoleAccessRepository) FindOne(queryOptions map[string]interface{}) (*domain.RoleAccess, error) {
  52 + tx := repository.transactionContext.PgTx
  53 + roleAccessModel := new(models.RoleAccess)
  54 + query := tx.Model(roleAccessModel)
  55 + if roleAccessId, ok := queryOptions["id"]; ok {
  56 + query = query.Where("role_access.id = ?", roleAccessId)
  57 + }
  58 + if err := query.First(); err != nil {
  59 + if err.Error() == "pg: no rows in result set" {
  60 + return nil, fmt.Errorf("没有此资源")
  61 + } else {
  62 + return nil, err
  63 + }
  64 + }
  65 + if roleAccessModel.Id == 0 {
  66 + return nil, nil
  67 + } else {
  68 + return repository.transformPgModelToDomainModel(roleAccessModel)
  69 + }
  70 +}
  71 +func (repository *RoleAccessRepository) Find(queryOptions map[string]interface{}) (int64, []*domain.RoleAccess, error) {
  72 + tx := repository.transactionContext.PgTx
  73 + var roleAccessModels []*models.RoleAccess
  74 + roleAccesss := make([]*domain.RoleAccess, 0)
  75 + query := tx.Model(&roleAccessModels)
  76 +
  77 + if roleId, ok := queryOptions["roleId"]; ok {
  78 + query = query.Where("role_id = ?", roleId)
  79 + }
  80 +
  81 + if offset, ok := queryOptions["offset"]; ok {
  82 + offset := offset.(int)
  83 + if offset > -1 {
  84 + query = query.Offset(offset)
  85 + }
  86 + } else {
  87 + query = query.Offset(0)
  88 + }
  89 + if limit, ok := queryOptions["limit"]; ok {
  90 + limit := limit.(int)
  91 + if limit > -1 {
  92 + query = query.Limit(limit)
  93 + }
  94 + } else {
  95 + query = query.Limit(20)
  96 + }
  97 + if count, err := query.Order("id DESC").SelectAndCount(); err != nil {
  98 + return 0, roleAccesss, err
  99 + } else {
  100 + for _, roleAccessModel := range roleAccessModels {
  101 + if roleAccess, err := repository.transformPgModelToDomainModel(roleAccessModel); err != nil {
  102 + return 0, roleAccesss, err
  103 + } else {
  104 + roleAccesss = append(roleAccesss, roleAccess)
  105 + }
  106 + }
  107 + return int64(count), roleAccesss, nil
  108 + }
  109 +}
  110 +func (repository *RoleAccessRepository) transformPgModelToDomainModel(roleAccessModel *models.RoleAccess) (*domain.RoleAccess, error) {
  111 + return &domain.RoleAccess{
  112 + Id: roleAccessModel.Id,
  113 + RoleId: roleAccessModel.RoleId,
  114 + AccessId: roleAccessModel.AccessId,
  115 + Object: roleAccessModel.Object,
  116 + Action: roleAccessModel.Action,
  117 + Option: roleAccessModel.Option,
  118 + }, nil
  119 +}
  120 +func NewRoleAccessRepository(transactionContext *pgTransaction.TransactionContext) (*RoleAccessRepository, error) {
  121 + if transactionContext == nil {
  122 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  123 + } else {
  124 + return &RoleAccessRepository{
  125 + transactionContext: transactionContext,
  126 + }, nil
  127 + }
  128 +}
  1 +package controllers
  2 +
  3 +import (
  4 + "encoding/json"
  5 +
  6 + "github.com/astaxie/beego"
  7 + "github.com/linmadan/egglib-go/web/beego/utils"
  8 + "github.com/tiptok/godevp/pkg/application/rbac/command"
  9 + "github.com/tiptok/godevp/pkg/application/rbac/query"
  10 + "github.com/tiptok/godevp/pkg/application/rbac/service"
  11 +)
  12 +
  13 +type RbacController struct {
  14 + beego.Controller
  15 +}
  16 +
  17 +func (controller *RbacController) Access() {
  18 + rbacService := service.NewRbacService(nil)
  19 + accessQuery := &query.AccessQuery{}
  20 + data, err := rbacService.Access(accessQuery)
  21 + var response utils.JsonResponse
  22 + if err != nil {
  23 + response = utils.ResponseError(controller.Ctx, err)
  24 + } else {
  25 + response = utils.ResponseData(controller.Ctx, data)
  26 + }
  27 + controller.Data["json"] = response
  28 + controller.ServeJSON()
  29 +}
  30 +
  31 +func (controller *RbacController) RoleAccess() {
  32 + rbacService := service.NewRbacService(nil)
  33 + roleAccessQuery := &query.RoleAccessQuery{}
  34 + roleId, _ := controller.GetInt64(":roleId")
  35 + roleAccessQuery.RoleId = roleId
  36 + data, err := rbacService.RoleAccess(roleAccessQuery)
  37 + var response utils.JsonResponse
  38 + if err != nil {
  39 + response = utils.ResponseError(controller.Ctx, err)
  40 + } else {
  41 + response = utils.ResponseData(controller.Ctx, data)
  42 + }
  43 + controller.Data["json"] = response
  44 + controller.ServeJSON()
  45 +}
  46 +
  47 +func (controller *RbacController) SetRoleAccess() {
  48 + rbacService := service.NewRbacService(nil)
  49 + setRoleAccessCommand := &command.SetRoleAccessCommand{}
  50 + json.Unmarshal(controller.Ctx.Input.GetData("requestBody").([]byte), setRoleAccessCommand)
  51 + data, err := rbacService.SetRoleAccess(setRoleAccessCommand)
  52 + var response utils.JsonResponse
  53 + if err != nil {
  54 + response = utils.ResponseError(controller.Ctx, err)
  55 + } else {
  56 + response = utils.ResponseData(controller.Ctx, data)
  57 + }
  58 + controller.Data["json"] = response
  59 + controller.ServeJSON()
  60 +}
  1 +package routers
  2 +
  3 +import (
  4 + "github.com/astaxie/beego"
  5 + "github.com/tiptok/godevp/pkg/port/beego/controllers"
  6 +)
  7 +
  8 +func init() {
  9 + beego.Router("/rbacs/access", &controllers.RbacController{}, "Get:Access")
  10 + beego.Router("/rbacs/roleAccess/:roleId", &controllers.RbacController{}, "Get:RoleAccess")
  11 + beego.Router("/rbacs/setRoleAccess", &controllers.RbacController{}, "Post:SetRoleAccess")
  12 +}
  1 +package model
  2 +
  3 +import (
  4 + "github.com/tiptok/gocomm/common"
  5 + domain "github.com/tiptok/godevp/pkg/domain/users"
  6 + "testing"
  7 + "time"
  8 + "unsafe"
  9 +)
  10 +
  11 +func TestUsers(t *testing.T) {
  12 + var u = &Users{}
  13 + var user = &domain.Users{
  14 + Name: "tiptok",
  15 + Phone: "1886018",
  16 + Roles: []int64{7, 8},
  17 + Status: 1,
  18 + CreateTime: time.Now(),
  19 + }
  20 + // 方法一:直接赋值
  21 + u.Name = &(user.Name)
  22 + // 方法二:使用unsafe.Pointer
  23 + u.Status = (*int)(unsafe.Pointer(&user.Status))
  24 + // 方法三: json-transfer
  25 + common.JsonUnmarshal(common.JsonAssertString(user), u)
  26 + if *(u.Name) != "tiptok" {
  27 +
  28 + }
  29 +}
  1 +package rbac
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/gavv/httpexpect"
  7 + "github.com/go-pg/pg"
  8 + . "github.com/onsi/ginkgo"
  9 + . "github.com/onsi/gomega"
  10 + pG "github.com/tiptok/godevp/pkg/infrastructure/pg"
  11 +)
  12 +
  13 +var _ = Describe("获取菜单列表", func() {
  14 + var Id int64
  15 + BeforeEach(func() {
  16 + _, err := pG.DB.QueryOne(
  17 + pg.Scan(&Id),
  18 + "INSERT INTO s () VALUES () RETURNING id",
  19 + )
  20 + Expect(err).NotTo(HaveOccurred())
  21 + })
  22 + Describe("获取菜单列表", func() {
  23 + Context("", func() {
  24 + It("", func() {
  25 + httpExpect := httpexpect.New(GinkgoT(), server.URL)
  26 + httpExpect.GET("/rbacs/access").
  27 + Expect().
  28 + Status(http.StatusOK).
  29 + JSON().
  30 + Object().
  31 + ContainsKey("code").ValueEqual("code", 0).
  32 + ContainsKey("msg").ValueEqual("msg", "ok").
  33 + ContainsKey("data").Value("data").Object()
  34 + })
  35 + })
  36 + })
  37 + AfterEach(func() {
  38 + _, err := pG.DB.Exec("DELETE FROM s WHERE true")
  39 + Expect(err).NotTo(HaveOccurred())
  40 + })
  41 +})
  1 +package rbac
  2 +
  3 +import (
  4 + "net/http"
  5 + "net/http/httptest"
  6 + "testing"
  7 +
  8 + "github.com/astaxie/beego"
  9 + . "github.com/onsi/ginkgo"
  10 + . "github.com/onsi/gomega"
  11 + _ "github.com/tiptok/godevp/pkg/infrastructure/pg"
  12 + _ "github.com/tiptok/godevp/pkg/port/beego"
  13 +)
  14 +
  15 +func TestRbac(t *testing.T) {
  16 + RegisterFailHandler(Fail)
  17 + RunSpecs(t, "Beego Port Rbac Correlations Test Case Suite")
  18 +}
  19 +
  20 +var handler http.Handler
  21 +var server *httptest.Server
  22 +
  23 +var _ = BeforeSuite(func() {
  24 + handler = beego.BeeApp.Handlers
  25 + server = httptest.NewServer(handler)
  26 +})
  27 +
  28 +var _ = AfterSuite(func() {
  29 + server.Close()
  30 +})
  1 +package rbac
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/gavv/httpexpect"
  7 + "github.com/go-pg/pg"
  8 + . "github.com/onsi/ginkgo"
  9 + . "github.com/onsi/gomega"
  10 + pG "github.com/tiptok/godevp/pkg/infrastructure/pg"
  11 +)
  12 +
  13 +var _ = Describe("角色权限", func() {
  14 + var Id int64
  15 + BeforeEach(func() {
  16 + _, err := pG.DB.QueryOne(
  17 + pg.Scan(&Id),
  18 + "INSERT INTO s () VALUES () RETURNING id",
  19 + )
  20 + Expect(err).NotTo(HaveOccurred())
  21 + })
  22 + Describe("角色权限", func() {
  23 + Context("", func() {
  24 + It("", func() {
  25 + httpExpect := httpexpect.New(GinkgoT(), server.URL)
  26 + httpExpect.GET("/rbacs/roleAccess/{roleId}").
  27 + Expect().
  28 + Status(http.StatusOK).
  29 + JSON().
  30 + Object().
  31 + ContainsKey("code").ValueEqual("code", 0).
  32 + ContainsKey("msg").ValueEqual("msg", "ok").
  33 + ContainsKey("data").Value("data").Object()
  34 + })
  35 + })
  36 + })
  37 + AfterEach(func() {
  38 + _, err := pG.DB.Exec("DELETE FROM s WHERE true")
  39 + Expect(err).NotTo(HaveOccurred())
  40 + })
  41 +})
  1 +package rbac
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/gavv/httpexpect"
  7 + "github.com/go-pg/pg"
  8 + . "github.com/onsi/ginkgo"
  9 + . "github.com/onsi/gomega"
  10 + pG "github.com/tiptok/godevp/pkg/infrastructure/pg"
  11 +)
  12 +
  13 +var _ = Describe("设置角色权限", func() {
  14 + var Id int64
  15 + BeforeEach(func() {
  16 + _, err := pG.DB.QueryOne(
  17 + pg.Scan(&Id),
  18 + "INSERT INTO s () VALUES () RETURNING id",
  19 + )
  20 + Expect(err).NotTo(HaveOccurred())
  21 + })
  22 + Describe("设置角色权限", func() {
  23 + Context("", func() {
  24 + It("", func() {
  25 + httpExpect := httpexpect.New(GinkgoT(), server.URL)
  26 + body := map[string]interface{}{
  27 + "roleId": "int64",
  28 + "accessIds": "array",
  29 + }
  30 + httpExpect.POST("/rbacs/setRoleAccess").
  31 + WithJSON(body).
  32 + Expect().
  33 + Status(http.StatusOK).
  34 + JSON().
  35 + Object().
  36 + ContainsKey("code").ValueEqual("code", 0).
  37 + ContainsKey("msg").ValueEqual("msg", "ok").
  38 + ContainsKey("data").Value("data").Object()
  39 + })
  40 + })
  41 + })
  42 + AfterEach(func() {
  43 + _, err := pG.DB.Exec("DELETE FROM s WHERE true")
  44 + Expect(err).NotTo(HaveOccurred())
  45 + })
  46 +})