refactor: split backend transport and domain modules
This commit is contained in:
parent
acba9624d7
commit
e6775f0966
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"kra/internal/conf"
|
||||
"kra/internal/server"
|
||||
"kra/internal/worker"
|
||||
|
||||
"github.com/go-kratos/kratos/contrib/otel/v3/tracing"
|
||||
"github.com/go-kratos/kratos/v3"
|
||||
|
|
@ -34,7 +35,7 @@ func init() {
|
|||
flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml")
|
||||
}
|
||||
|
||||
func newApp(logger *slog.Logger, hs *server.GinServer, scheduler *server.TaskScheduler) *kratos.App {
|
||||
func newApp(logger *slog.Logger, hs *server.GinServer, scheduler *worker.TaskScheduler) *kratos.App {
|
||||
return kratos.New(
|
||||
kratos.ID(id),
|
||||
kratos.Name(Name),
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ import (
|
|||
"kra/internal/conf"
|
||||
"kra/internal/data"
|
||||
"kra/internal/server"
|
||||
"kra/internal/server/handler"
|
||||
"kra/internal/service"
|
||||
"kra/internal/worker"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
|
|
@ -43,6 +45,32 @@ func wireApp(confServer *conf.Server, confData *conf.Data, adminBackend *conf.Ad
|
|||
accessRepo := data.NewAccessRepo(dataData)
|
||||
accessUsecase := biz.NewAccessUsecase(accessRepo)
|
||||
accessService := service.NewAccessService(accessUsecase)
|
||||
authority := handler.NewAuthority(accessService)
|
||||
menuRepo := data.NewMenuRepo(dataData)
|
||||
menuUsecase := biz.NewMenuUsecase(menuRepo)
|
||||
menuService := service.NewMenuService(menuUsecase)
|
||||
menu := handler.NewMenu(menuService)
|
||||
api := handler.NewAPI(accessService)
|
||||
permission := handler.NewPermission(accessService)
|
||||
organizationRepo := data.NewOrganizationRepo(dataData)
|
||||
organizationUsecase := biz.NewOrganizationUsecase(organizationRepo)
|
||||
organizationService := service.NewOrganizationService(organizationUsecase)
|
||||
organization := handler.NewOrganization(organizationService)
|
||||
announcementRepo := data.NewAnnouncementRepo(dataData)
|
||||
announcementUsecase := biz.NewAnnouncementUsecase(announcementRepo)
|
||||
announcementService := service.NewAnnouncementService(announcementUsecase)
|
||||
announcement := handler.NewAnnouncement(announcementService)
|
||||
emailRepo := data.NewEmailRepo(adminBackend)
|
||||
emailUsecase := biz.NewEmailUsecase(emailRepo)
|
||||
emailService := service.NewEmailService(emailUsecase)
|
||||
email := handler.NewEmail(emailService)
|
||||
taskRepo := data.NewTaskRepo(dataData)
|
||||
taskUsecase := biz.NewTaskUsecase(taskRepo)
|
||||
mediaRepo := data.NewMediaRepo(dataData)
|
||||
mediaUsecase := biz.NewMediaUsecase(mediaRepo, fileStorage)
|
||||
taskService := service.NewTaskService(taskUsecase, mediaUsecase, adminBackend)
|
||||
taskScheduler := worker.NewTaskScheduler(taskService, logger)
|
||||
task := handler.NewTask(taskService, taskScheduler)
|
||||
versionRepo := data.NewVersionRepo(dataData)
|
||||
versionUsecase := biz.NewVersionUsecase(versionRepo)
|
||||
versionService := service.NewVersionService(versionUsecase)
|
||||
|
|
@ -52,20 +80,8 @@ func wireApp(confServer *conf.Server, confData *conf.Data, adminBackend *conf.Ad
|
|||
auditRepo := data.NewAuditRepo(dataData)
|
||||
auditUsecase := biz.NewAuditUsecase(auditRepo)
|
||||
auditService := service.NewAuditService(auditUsecase)
|
||||
taskRepo := data.NewTaskRepo(dataData)
|
||||
taskUsecase := biz.NewTaskUsecase(taskRepo)
|
||||
mediaRepo := data.NewMediaRepo(dataData)
|
||||
mediaUsecase := biz.NewMediaUsecase(mediaRepo, fileStorage)
|
||||
taskService := service.NewTaskService(taskUsecase, mediaUsecase, adminBackend)
|
||||
mediaService := service.NewMediaService(mediaUsecase)
|
||||
announcementRepo := data.NewAnnouncementRepo(dataData)
|
||||
announcementUsecase := biz.NewAnnouncementUsecase(announcementRepo)
|
||||
announcementService := service.NewAnnouncementService(announcementUsecase)
|
||||
emailRepo := data.NewEmailRepo(adminBackend)
|
||||
emailUsecase := biz.NewEmailUsecase(emailRepo)
|
||||
emailService := service.NewEmailService(emailUsecase)
|
||||
taskScheduler := server.NewTaskScheduler(taskService, logger)
|
||||
ginServer := server.NewGinServer(confServer, adminBackend, systemService, accessService, settingsService, versionService, exportService, auditService, taskService, mediaService, announcementService, emailService, taskScheduler, logger)
|
||||
ginServer := server.NewGinServer(confServer, adminBackend, systemService, accessService, authority, menu, api, permission, organization, announcement, email, task, settingsService, versionService, exportService, auditService, mediaService, emailService, taskScheduler, logger)
|
||||
app := newApp(logger, ginServer, taskScheduler)
|
||||
return app, func() {
|
||||
cleanup()
|
||||
|
|
|
|||
6
go.sum
6
go.sum
|
|
@ -175,6 +175,8 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
|
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
|
|
@ -388,6 +390,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
|
||||
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
|
@ -483,6 +487,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
|
||||
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
|
|
|
|||
|
|
@ -15,69 +15,18 @@ type API struct {
|
|||
Method string
|
||||
}
|
||||
|
||||
type MenuButton struct {
|
||||
ID uint
|
||||
Name string
|
||||
Description string
|
||||
MenuID uint
|
||||
AuthorityID uint
|
||||
}
|
||||
|
||||
type MenuParameter struct {
|
||||
ID uint
|
||||
MenuID uint
|
||||
Type string
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
type Department struct {
|
||||
ID uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Name string
|
||||
ParentID uint
|
||||
Ancestors string
|
||||
Sort int
|
||||
LeaderID uint
|
||||
Status bool
|
||||
Children []*Department
|
||||
}
|
||||
|
||||
type Position struct {
|
||||
ID uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Name string
|
||||
Code string
|
||||
Sort int
|
||||
Status bool
|
||||
Remark string
|
||||
}
|
||||
|
||||
type AccessRepo interface {
|
||||
CreateAuthority(context.Context, *Authority) error
|
||||
CopyAuthority(context.Context, uint, *Authority) error
|
||||
UpdateAuthority(context.Context, *Authority) error
|
||||
DeleteAuthority(context.Context, uint) error
|
||||
ListAuthorities(context.Context) ([]*Authority, error)
|
||||
SetAuthorityMenus(context.Context, uint, []uint) error
|
||||
AuthorityMenuIDs(context.Context, uint) ([]uint, error)
|
||||
SetAuthorityUsers(context.Context, uint, []uint) error
|
||||
AuthorityUserIDs(context.Context, uint) ([]uint, error)
|
||||
SetDataScope(context.Context, uint, int, []uint) error
|
||||
DataScopeDepartmentIDs(context.Context, uint) ([]uint, error)
|
||||
ResolveDataScope(context.Context, uint, uint) (DataScope, error)
|
||||
|
||||
CreateMenu(context.Context, *Menu) error
|
||||
UpdateMenu(context.Context, *Menu) error
|
||||
DeleteMenu(context.Context, uint) error
|
||||
FindMenu(context.Context, uint) (*Menu, error)
|
||||
ListMenus(context.Context) ([]*Menu, error)
|
||||
MenuRoleIDs(context.Context, uint) ([]uint, error)
|
||||
SetMenuRoles(context.Context, uint, []uint) error
|
||||
ReplaceMenuButtons(context.Context, uint, []*MenuButton) error
|
||||
|
||||
CreateAPI(context.Context, *API) error
|
||||
UpdateAPI(context.Context, *API) error
|
||||
DeleteAPIs(context.Context, []uint) error
|
||||
|
|
@ -98,24 +47,6 @@ type AccessRepo interface {
|
|||
SelectedButtons(context.Context, uint, uint) ([]uint, error)
|
||||
SetSelectedButtons(context.Context, uint, uint, []uint) error
|
||||
CanRemoveButton(context.Context, uint) (bool, error)
|
||||
|
||||
CreateDepartment(context.Context, *Department) error
|
||||
UpdateDepartment(context.Context, *Department) error
|
||||
DeleteDepartment(context.Context, uint) error
|
||||
FindDepartment(context.Context, uint) (*Department, error)
|
||||
ListDepartments(context.Context, string) ([]*Department, error)
|
||||
DepartmentUserIDs(context.Context, uint) ([]uint, error)
|
||||
SetDepartmentUsers(context.Context, uint, []uint) error
|
||||
SetUserDepartments(context.Context, uint, []uint, uint) error
|
||||
|
||||
CreatePosition(context.Context, *Position) error
|
||||
UpdatePosition(context.Context, *Position) error
|
||||
DeletePosition(context.Context, uint) error
|
||||
FindPosition(context.Context, uint) (*Position, error)
|
||||
ListPositions(context.Context, int, int, *Position) ([]*Position, int64, error)
|
||||
PositionUserIDs(context.Context, uint) ([]uint, error)
|
||||
SetPositionUsers(context.Context, uint, []uint) error
|
||||
SetUserPositions(context.Context, uint, []uint) error
|
||||
}
|
||||
|
||||
type AccessUsecase struct{ repo AccessRepo }
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ package biz
|
|||
import "github.com/google/wire"
|
||||
|
||||
// ProviderSet is biz providers.
|
||||
var ProviderSet = wire.NewSet(NewSystemUsecase, NewAccessUsecase, NewSettingsUsecase, NewVersionUsecase, NewExportUsecase, NewAuditUsecase, NewTaskUsecase, NewMediaUsecase, NewAnnouncementUsecase, NewEmailUsecase)
|
||||
var ProviderSet = wire.NewSet(NewSystemUsecase, NewAccessUsecase, NewMenuUsecase, NewOrganizationUsecase, NewSettingsUsecase, NewVersionUsecase, NewExportUsecase, NewAuditUsecase, NewTaskUsecase, NewMediaUsecase, NewAnnouncementUsecase, NewEmailUsecase)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
package biz
|
||||
|
||||
import "context"
|
||||
|
||||
type MenuButton struct {
|
||||
ID uint
|
||||
Name string
|
||||
Description string
|
||||
MenuID uint
|
||||
AuthorityID uint
|
||||
}
|
||||
|
||||
type MenuParameter struct {
|
||||
ID uint
|
||||
MenuID uint
|
||||
Type string
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
type Menu struct {
|
||||
ID uint
|
||||
ParentID uint
|
||||
Path string
|
||||
Name string
|
||||
Hidden bool
|
||||
Component string
|
||||
Sort int
|
||||
ActiveName string
|
||||
KeepAlive bool
|
||||
DefaultMenu bool
|
||||
Title string
|
||||
Icon string
|
||||
CloseTab bool
|
||||
TransitionType string
|
||||
Children []*Menu
|
||||
Buttons []*MenuButton
|
||||
Parameters []*MenuParameter
|
||||
}
|
||||
|
||||
type MenuRepo interface {
|
||||
Create(context.Context, *Menu) error
|
||||
Update(context.Context, *Menu) error
|
||||
Delete(context.Context, uint) error
|
||||
Find(context.Context, uint) (*Menu, error)
|
||||
List(context.Context) ([]*Menu, error)
|
||||
SetAuthorityMenus(context.Context, uint, []uint) error
|
||||
AuthorityMenuIDs(context.Context, uint) ([]uint, error)
|
||||
MenuRoleIDs(context.Context, uint) ([]uint, error)
|
||||
SetMenuRoles(context.Context, uint, []uint) error
|
||||
}
|
||||
|
||||
type MenuUsecase struct{ repo MenuRepo }
|
||||
|
||||
func NewMenuUsecase(repo MenuRepo) *MenuUsecase { return &MenuUsecase{repo: repo} }
|
||||
|
||||
func (uc *MenuUsecase) List(ctx context.Context) ([]*Menu, error) {
|
||||
return uc.repo.List(ctx)
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) Tree(ctx context.Context) ([]*Menu, error) {
|
||||
items, err := uc.repo.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byID := make(map[uint]*Menu, len(items))
|
||||
for _, item := range items {
|
||||
item.Children = []*Menu{}
|
||||
byID[item.ID] = item
|
||||
}
|
||||
roots := make([]*Menu, 0)
|
||||
for _, item := range items {
|
||||
if parent := byID[item.ParentID]; parent != nil {
|
||||
parent.Children = append(parent.Children, item)
|
||||
} else {
|
||||
roots = append(roots, item)
|
||||
}
|
||||
}
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) Create(ctx context.Context, menu *Menu) error {
|
||||
return uc.repo.Create(ctx, menu)
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) Update(ctx context.Context, menu *Menu) error {
|
||||
return uc.repo.Update(ctx, menu)
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) Delete(ctx context.Context, id uint) error {
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) Find(ctx context.Context, id uint) (*Menu, error) {
|
||||
return uc.repo.Find(ctx, id)
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) SetAuthorityMenus(ctx context.Context, authorityID uint, ids []uint) error {
|
||||
return uc.repo.SetAuthorityMenus(ctx, authorityID, ids)
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) AuthorityMenus(ctx context.Context, authorityID uint) ([]*Menu, error) {
|
||||
ids, err := uc.repo.AuthorityMenuIDs(ctx, authorityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items, err := uc.repo.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selected := make(map[uint]struct{}, len(ids))
|
||||
for _, id := range ids {
|
||||
selected[id] = struct{}{}
|
||||
}
|
||||
result := make([]*Menu, 0, len(ids))
|
||||
for _, item := range items {
|
||||
if _, ok := selected[item.ID]; ok {
|
||||
// The authority-menu endpoint returns menu relations only. Keep its
|
||||
// existing contract: button details are loaded by the dedicated
|
||||
// authority-button endpoints.
|
||||
item.Buttons = nil
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) RoleIDs(ctx context.Context, menuID uint) ([]uint, error) {
|
||||
return uc.repo.MenuRoleIDs(ctx, menuID)
|
||||
}
|
||||
|
||||
func (uc *MenuUsecase) SetRoles(ctx context.Context, menuID uint, ids []uint) error {
|
||||
return uc.repo.SetMenuRoles(ctx, menuID, ids)
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Department struct {
|
||||
ID uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Name string
|
||||
ParentID uint
|
||||
Ancestors string
|
||||
Sort int
|
||||
LeaderID uint
|
||||
Status bool
|
||||
Children []*Department
|
||||
}
|
||||
|
||||
type Position struct {
|
||||
ID uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Name string
|
||||
Code string
|
||||
Sort int
|
||||
Status bool
|
||||
Remark string
|
||||
}
|
||||
|
||||
type OrganizationRepo interface {
|
||||
CreateDepartment(context.Context, *Department) error
|
||||
UpdateDepartment(context.Context, *Department) error
|
||||
DeleteDepartment(context.Context, uint) error
|
||||
FindDepartment(context.Context, uint) (*Department, error)
|
||||
ListDepartments(context.Context, string) ([]*Department, error)
|
||||
DepartmentUserIDs(context.Context, uint) ([]uint, error)
|
||||
SetDepartmentUsers(context.Context, uint, []uint) error
|
||||
SetUserDepartments(context.Context, uint, []uint, uint) error
|
||||
CreatePosition(context.Context, *Position) error
|
||||
UpdatePosition(context.Context, *Position) error
|
||||
DeletePosition(context.Context, uint) error
|
||||
FindPosition(context.Context, uint) (*Position, error)
|
||||
ListPositions(context.Context, int, int, *Position) ([]*Position, int64, error)
|
||||
PositionUserIDs(context.Context, uint) ([]uint, error)
|
||||
SetPositionUsers(context.Context, uint, []uint) error
|
||||
SetUserPositions(context.Context, uint, []uint) error
|
||||
}
|
||||
|
||||
type OrganizationUsecase struct{ repo OrganizationRepo }
|
||||
|
||||
func NewOrganizationUsecase(repo OrganizationRepo) *OrganizationUsecase {
|
||||
return &OrganizationUsecase{repo: repo}
|
||||
}
|
||||
|
||||
func (uc *OrganizationUsecase) Departments(ctx context.Context, name string) ([]*Department, error) {
|
||||
return uc.repo.ListDepartments(ctx, name)
|
||||
}
|
||||
func (uc *OrganizationUsecase) CreateDepartment(ctx context.Context, value *Department) error {
|
||||
return uc.repo.CreateDepartment(ctx, value)
|
||||
}
|
||||
func (uc *OrganizationUsecase) UpdateDepartment(ctx context.Context, value *Department) error {
|
||||
return uc.repo.UpdateDepartment(ctx, value)
|
||||
}
|
||||
func (uc *OrganizationUsecase) DeleteDepartment(ctx context.Context, id uint) error {
|
||||
return uc.repo.DeleteDepartment(ctx, id)
|
||||
}
|
||||
func (uc *OrganizationUsecase) Department(ctx context.Context, id uint) (*Department, error) {
|
||||
return uc.repo.FindDepartment(ctx, id)
|
||||
}
|
||||
func (uc *OrganizationUsecase) DepartmentUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return uc.repo.DepartmentUserIDs(ctx, id)
|
||||
}
|
||||
func (uc *OrganizationUsecase) SetDepartmentUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return uc.repo.SetDepartmentUsers(ctx, id, ids)
|
||||
}
|
||||
func (uc *OrganizationUsecase) SetUserDepartments(ctx context.Context, id uint, ids []uint, primary uint) error {
|
||||
return uc.repo.SetUserDepartments(ctx, id, ids, primary)
|
||||
}
|
||||
func (uc *OrganizationUsecase) Positions(ctx context.Context, page, size int, filter *Position) ([]*Position, int64, error) {
|
||||
return uc.repo.ListPositions(ctx, page, size, filter)
|
||||
}
|
||||
func (uc *OrganizationUsecase) CreatePosition(ctx context.Context, value *Position) error {
|
||||
return uc.repo.CreatePosition(ctx, value)
|
||||
}
|
||||
func (uc *OrganizationUsecase) UpdatePosition(ctx context.Context, value *Position) error {
|
||||
return uc.repo.UpdatePosition(ctx, value)
|
||||
}
|
||||
func (uc *OrganizationUsecase) DeletePosition(ctx context.Context, id uint) error {
|
||||
return uc.repo.DeletePosition(ctx, id)
|
||||
}
|
||||
func (uc *OrganizationUsecase) Position(ctx context.Context, id uint) (*Position, error) {
|
||||
return uc.repo.FindPosition(ctx, id)
|
||||
}
|
||||
func (uc *OrganizationUsecase) PositionUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return uc.repo.PositionUserIDs(ctx, id)
|
||||
}
|
||||
func (uc *OrganizationUsecase) SetPositionUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return uc.repo.SetPositionUsers(ctx, id, ids)
|
||||
}
|
||||
func (uc *OrganizationUsecase) SetUserPositions(ctx context.Context, id uint, ids []uint) error {
|
||||
return uc.repo.SetUserPositions(ctx, id, ids)
|
||||
}
|
||||
|
|
@ -48,26 +48,6 @@ type Authority struct {
|
|||
DefaultRouter string
|
||||
}
|
||||
|
||||
type Menu struct {
|
||||
ID uint
|
||||
ParentID uint
|
||||
Path string
|
||||
Name string
|
||||
Hidden bool
|
||||
Component string
|
||||
Sort int
|
||||
ActiveName string
|
||||
KeepAlive bool
|
||||
DefaultMenu bool
|
||||
Title string
|
||||
Icon string
|
||||
CloseTab bool
|
||||
TransitionType string
|
||||
Children []*Menu
|
||||
Buttons []*MenuButton
|
||||
Parameters []*MenuParameter
|
||||
}
|
||||
|
||||
type SystemRepo interface {
|
||||
IsInitialized(context.Context) (bool, error)
|
||||
Initialize(context.Context, *DatabaseConfig) error
|
||||
|
|
|
|||
|
|
@ -109,8 +109,10 @@ type authorityDepartmentPO struct {
|
|||
func (authorityDepartmentPO) TableName() string { return "sys_authority_departments" }
|
||||
|
||||
type accessRepo struct{ data *Data }
|
||||
type organizationRepo struct{ data *Data }
|
||||
|
||||
func NewAccessRepo(data *Data) biz.AccessRepo { return &accessRepo{data: data} }
|
||||
func NewAccessRepo(data *Data) biz.AccessRepo { return &accessRepo{data: data} }
|
||||
func NewOrganizationRepo(data *Data) biz.OrganizationRepo { return &organizationRepo{data: data} }
|
||||
|
||||
func (r *accessRepo) CreateAuthority(ctx context.Context, value *biz.Authority) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
|
|
@ -263,26 +265,6 @@ func (r *accessRepo) ListAuthorities(ctx context.Context) ([]*biz.Authority, err
|
|||
}
|
||||
return out, nil
|
||||
}
|
||||
func (r *accessRepo) SetAuthorityMenus(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("sys_authority_authority_id = ?", id).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
links := make([]authorityMenuPO, 0, len(ids))
|
||||
for _, mid := range ids {
|
||||
links = append(links, authorityMenuPO{SysAuthorityAuthorityID: id, SysBaseMenuID: mid})
|
||||
}
|
||||
if len(links) > 0 {
|
||||
return tx.Create(&links).Error
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
func (r *accessRepo) AuthorityMenuIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := r.data.gormDB.WithContext(ctx).Model(&authorityMenuPO{}).Where("sys_authority_authority_id = ?", id).Pluck("sys_base_menu_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
func (r *accessRepo) SetAuthorityUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var oldIDs []uint
|
||||
|
|
@ -403,228 +385,6 @@ func (r *accessRepo) ResolveDataScope(ctx context.Context, authorityID, userID u
|
|||
return biz.DataScope{DepartmentIDs: ids}, nil
|
||||
}
|
||||
|
||||
func menuFromPO(po menuPO) *biz.Menu {
|
||||
return &biz.Menu{ID: po.ID, ParentID: po.ParentID, Path: po.Path, Name: po.Name, Hidden: po.Hidden, Component: po.Component, Sort: po.Sort, ActiveName: po.ActiveName, KeepAlive: po.KeepAlive, DefaultMenu: po.DefaultMenu, Title: po.Title, Icon: po.Icon, CloseTab: po.CloseTab, TransitionType: po.TransitionType}
|
||||
}
|
||||
func menuToPO(v *biz.Menu) menuPO {
|
||||
return menuPO{ID: v.ID, ParentID: v.ParentID, Path: v.Path, Name: v.Name, Hidden: v.Hidden, Component: v.Component, Sort: v.Sort, ActiveName: v.ActiveName, KeepAlive: v.KeepAlive, DefaultMenu: v.DefaultMenu, Title: v.Title, Icon: v.Icon, CloseTab: v.CloseTab, TransitionType: v.TransitionType}
|
||||
}
|
||||
func replaceMenuRelations(tx *gorm.DB, menu *biz.Menu) error {
|
||||
var oldButtonIDs []uint
|
||||
if err := tx.Model(&menuButtonPO{}).Where("sys_base_menu_id = ?", menu.ID).Pluck("id", &oldButtonIDs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if len(oldButtonIDs) > 0 {
|
||||
if err := tx.Where("sys_base_menu_btn_id IN ?", oldButtonIDs).Delete(&authorityButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", menu.ID).Delete(&menuButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", menu.ID).Delete(&menuParameterPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
buttons := make([]menuButtonPO, 0, len(menu.Buttons))
|
||||
for _, button := range menu.Buttons {
|
||||
buttons = append(buttons, menuButtonPO{Name: button.Name, Description: button.Description, MenuID: menu.ID})
|
||||
}
|
||||
if len(buttons) > 0 {
|
||||
if err := tx.Create(&buttons).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
parameters := make([]menuParameterPO, 0, len(menu.Parameters))
|
||||
for _, parameter := range menu.Parameters {
|
||||
parameters = append(parameters, menuParameterPO{MenuID: menu.ID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
|
||||
}
|
||||
if len(parameters) > 0 {
|
||||
return tx.Create(¶meters).Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (r *accessRepo) CreateMenu(ctx context.Context, v *biz.Menu) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var count int64
|
||||
if err := tx.Model(&menuPO{}).Where("name = ?", v.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("存在重复name,请修改name")
|
||||
}
|
||||
if v.ParentID != 0 {
|
||||
var parent menuPO
|
||||
if err := tx.First(&parent, v.ParentID).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New("父菜单不存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := tx.Model(&menuPO{}).Where("parent_id = ?", v.ParentID).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
if err := tx.Model(&authorityPO{}).Where("default_router = ?", parent.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("父菜单已被其他角色的首页占用,请先释放父菜单的首页权限")
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", v.ParentID).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
po := menuToPO(v)
|
||||
if err := tx.Create(&po).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
v.ID = po.ID
|
||||
return replaceMenuRelations(tx, v)
|
||||
})
|
||||
}
|
||||
func (r *accessRepo) UpdateMenu(ctx context.Context, v *biz.Menu) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var old menuPO
|
||||
if err := tx.First(&old, v.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
var count int64
|
||||
if old.Name != v.Name {
|
||||
if err := tx.Model(&menuPO{}).Where("id <> ? AND name = ?", v.ID, v.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("存在相同name修改失败")
|
||||
}
|
||||
}
|
||||
if err := replaceMenuRelations(tx, v); err != nil {
|
||||
return err
|
||||
}
|
||||
values := map[string]any{"parent_id": v.ParentID, "path": v.Path, "name": v.Name, "hidden": v.Hidden, "component": v.Component, "sort": v.Sort, "active_name": v.ActiveName, "keep_alive": v.KeepAlive, "default_menu": v.DefaultMenu, "title": v.Title, "icon": v.Icon, "close_tab": v.CloseTab, "transition_type": v.TransitionType}
|
||||
return tx.Model(&old).Updates(values).Error
|
||||
})
|
||||
}
|
||||
func (r *accessRepo) DeleteMenu(ctx context.Context, id uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var count int64
|
||||
if err := tx.Model(&menuPO{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("此菜单存在子菜单不可删除")
|
||||
}
|
||||
var menu menuPO
|
||||
if err := tx.First(&menu, id).Error; err != nil {
|
||||
return errors.New("记录不存在")
|
||||
}
|
||||
if err := tx.Model(&authorityPO{}).Where("default_router = ?", menu.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("此菜单有角色正在作为首页,不可删除")
|
||||
}
|
||||
var buttonIDs []uint
|
||||
if err := tx.Model(&menuButtonPO{}).Where("sys_base_menu_id = ?", id).Pluck("id", &buttonIDs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_menu_id = ?", id).Delete(&authorityButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&menuButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&menuParameterPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Delete(&menuPO{}, id).Error
|
||||
})
|
||||
}
|
||||
func (r *accessRepo) FindMenu(ctx context.Context, id uint) (*biz.Menu, error) {
|
||||
var po menuPO
|
||||
if err := r.data.gormDB.WithContext(ctx).First(&po, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
menu := menuFromPO(po)
|
||||
if err := r.loadMenuParameters(ctx, menu); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menu, nil
|
||||
}
|
||||
func (r *accessRepo) loadMenuParameters(ctx context.Context, menu *biz.Menu) error {
|
||||
var pos []menuParameterPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id = ?", menu.ID).Order("id").Find(&pos).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
menu.Parameters = make([]*biz.MenuParameter, 0, len(pos))
|
||||
for _, po := range pos {
|
||||
menu.Parameters = append(menu.Parameters, &biz.MenuParameter{ID: po.ID, MenuID: po.MenuID, Type: po.Type, Key: po.Key, Value: po.Value})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (r *accessRepo) ListMenus(ctx context.Context) ([]*biz.Menu, error) {
|
||||
var pos []menuPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Order("sort,id").Find(&pos).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]*biz.Menu, 0, len(pos))
|
||||
for _, po := range pos {
|
||||
menu := menuFromPO(po)
|
||||
if err := r.loadMenuParameters(ctx, menu); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, menu)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (r *accessRepo) MenuRoleIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := r.data.gormDB.WithContext(ctx).Model(&authorityMenuPO{}).Where("sys_base_menu_id = ?", id).Pluck("sys_authority_authority_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
func (r *accessRepo) SetMenuRoles(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
links := make([]authorityMenuPO, 0, len(ids))
|
||||
for _, aid := range ids {
|
||||
links = append(links, authorityMenuPO{SysAuthorityAuthorityID: aid, SysBaseMenuID: id})
|
||||
}
|
||||
if len(links) > 0 {
|
||||
return tx.Create(&links).Error
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
func (r *accessRepo) ReplaceMenuButtons(ctx context.Context, menuID uint, buttons []*biz.MenuButton) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var oldIDs []uint
|
||||
if err := tx.Model(&menuButtonPO{}).Where("sys_base_menu_id = ?", menuID).Pluck("id", &oldIDs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if len(oldIDs) > 0 {
|
||||
if err := tx.Where("sys_base_menu_btn_id IN ?", oldIDs).Delete(&authorityButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", menuID).Delete(&menuButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
pos := make([]menuButtonPO, 0, len(buttons))
|
||||
for _, button := range buttons {
|
||||
pos = append(pos, menuButtonPO{Name: button.Name, Description: button.Description, MenuID: menuID})
|
||||
}
|
||||
if len(pos) > 0 {
|
||||
return tx.Create(&pos).Error
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func apiFromPO(po apiPO) *biz.API {
|
||||
return &biz.API{ID: po.ID, CreatedAt: po.CreatedAt, UpdatedAt: po.UpdatedAt, Path: po.Path, Description: po.Description, APIGroup: po.APIGroup, Method: po.Method}
|
||||
}
|
||||
|
|
@ -874,7 +634,7 @@ func (r *accessRepo) AuthorityButtonIDs(ctx context.Context, aid uint) ([]uint,
|
|||
func deptFromPO(po departmentPO) *biz.Department {
|
||||
return &biz.Department{ID: po.ID, CreatedAt: po.CreatedAt, UpdatedAt: po.UpdatedAt, Name: po.Name, ParentID: po.ParentID, Ancestors: po.Ancestors, Sort: po.Sort, LeaderID: po.LeaderID, Status: po.Status}
|
||||
}
|
||||
func (r *accessRepo) CreateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
func (r *organizationRepo) CreateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
v.Ancestors = "0"
|
||||
if v.ParentID != 0 {
|
||||
var parent departmentPO
|
||||
|
|
@ -885,7 +645,7 @@ func (r *accessRepo) CreateDepartment(ctx context.Context, v *biz.Department) er
|
|||
}
|
||||
return r.data.gormDB.WithContext(ctx).Create(&departmentPO{Name: v.Name, ParentID: v.ParentID, Ancestors: v.Ancestors, Sort: v.Sort, LeaderID: v.LeaderID, Status: v.Status}).Error
|
||||
}
|
||||
func (r *accessRepo) UpdateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
func (r *organizationRepo) UpdateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
if v.ParentID == v.ID {
|
||||
return errors.New("父部门不能是自己")
|
||||
}
|
||||
|
|
@ -899,7 +659,7 @@ func (r *accessRepo) UpdateDepartment(ctx context.Context, v *biz.Department) er
|
|||
}
|
||||
return r.data.gormDB.WithContext(ctx).Model(&departmentPO{}).Where("id = ?", v.ID).Updates(map[string]any{"name": v.Name, "parent_id": v.ParentID, "ancestors": v.Ancestors, "sort": v.Sort, "leader_id": v.LeaderID, "status": v.Status}).Error
|
||||
}
|
||||
func (r *accessRepo) DeleteDepartment(ctx context.Context, id uint) error {
|
||||
func (r *organizationRepo) DeleteDepartment(ctx context.Context, id uint) error {
|
||||
if id == 0 {
|
||||
return errors.New("部门ID不能为空")
|
||||
}
|
||||
|
|
@ -924,14 +684,14 @@ func (r *accessRepo) DeleteDepartment(ctx context.Context, id uint) error {
|
|||
}
|
||||
return r.data.gormDB.WithContext(ctx).Delete(&departmentPO{}, id).Error
|
||||
}
|
||||
func (r *accessRepo) FindDepartment(ctx context.Context, id uint) (*biz.Department, error) {
|
||||
func (r *organizationRepo) FindDepartment(ctx context.Context, id uint) (*biz.Department, error) {
|
||||
var po departmentPO
|
||||
if err := r.data.gormDB.WithContext(ctx).First(&po, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return deptFromPO(po), nil
|
||||
}
|
||||
func (r *accessRepo) ListDepartments(ctx context.Context, name string) ([]*biz.Department, error) {
|
||||
func (r *organizationRepo) ListDepartments(ctx context.Context, name string) ([]*biz.Department, error) {
|
||||
var pos []departmentPO
|
||||
db := r.data.gormDB.WithContext(ctx).Order("sort,id")
|
||||
if name != "" {
|
||||
|
|
@ -955,15 +715,15 @@ func (r *accessRepo) ListDepartments(ctx context.Context, name string) ([]*biz.D
|
|||
}
|
||||
return roots, nil
|
||||
}
|
||||
func (r *accessRepo) DepartmentUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
func (r *organizationRepo) DepartmentUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := r.data.gormDB.WithContext(ctx).Model(&userDepartmentPO{}).Where("sys_department_id = ?", id).Pluck("sys_user_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
func (r *accessRepo) SetDepartmentUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
func (r *organizationRepo) SetDepartmentUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.replaceUserDepartments(ctx, id, ids)
|
||||
}
|
||||
func (r *accessRepo) replaceUserDepartments(ctx context.Context, id uint, ids []uint) error {
|
||||
func (r *organizationRepo) replaceUserDepartments(ctx context.Context, id uint, ids []uint) error {
|
||||
if id == 0 {
|
||||
return errors.New("部门ID不能为空")
|
||||
}
|
||||
|
|
@ -1007,7 +767,7 @@ func (r *accessRepo) replaceUserDepartments(ctx context.Context, id uint, ids []
|
|||
return nil
|
||||
})
|
||||
}
|
||||
func (r *accessRepo) SetUserDepartments(ctx context.Context, uid uint, ids []uint, primary uint) error {
|
||||
func (r *organizationRepo) SetUserDepartments(ctx context.Context, uid uint, ids []uint, primary uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var user userPO
|
||||
if err := tx.First(&user, uid).Error; err != nil {
|
||||
|
|
@ -1047,13 +807,13 @@ func (r *accessRepo) SetUserDepartments(ctx context.Context, uid uint, ids []uin
|
|||
func posFromPO(po positionPO) *biz.Position {
|
||||
return &biz.Position{ID: po.ID, CreatedAt: po.CreatedAt, UpdatedAt: po.UpdatedAt, Name: po.Name, Code: po.Code, Sort: po.Sort, Status: po.Status, Remark: po.Remark}
|
||||
}
|
||||
func (r *accessRepo) CreatePosition(ctx context.Context, v *biz.Position) error {
|
||||
func (r *organizationRepo) CreatePosition(ctx context.Context, v *biz.Position) error {
|
||||
return r.data.gormDB.WithContext(ctx).Create(&positionPO{Name: v.Name, Code: v.Code, Sort: v.Sort, Status: v.Status, Remark: v.Remark}).Error
|
||||
}
|
||||
func (r *accessRepo) UpdatePosition(ctx context.Context, v *biz.Position) error {
|
||||
func (r *organizationRepo) UpdatePosition(ctx context.Context, v *biz.Position) error {
|
||||
return r.data.gormDB.WithContext(ctx).Model(&positionPO{}).Where("id = ?", v.ID).Updates(map[string]any{"name": v.Name, "code": v.Code, "sort": v.Sort, "status": v.Status, "remark": v.Remark}).Error
|
||||
}
|
||||
func (r *accessRepo) DeletePosition(ctx context.Context, id uint) error {
|
||||
func (r *organizationRepo) DeletePosition(ctx context.Context, id uint) error {
|
||||
if id == 0 {
|
||||
return errors.New("岗位ID不能为空")
|
||||
}
|
||||
|
|
@ -1066,14 +826,14 @@ func (r *accessRepo) DeletePosition(ctx context.Context, id uint) error {
|
|||
}
|
||||
return r.data.gormDB.WithContext(ctx).Delete(&positionPO{}, id).Error
|
||||
}
|
||||
func (r *accessRepo) FindPosition(ctx context.Context, id uint) (*biz.Position, error) {
|
||||
func (r *organizationRepo) FindPosition(ctx context.Context, id uint) (*biz.Position, error) {
|
||||
var po positionPO
|
||||
if err := r.data.gormDB.WithContext(ctx).First(&po, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return posFromPO(po), nil
|
||||
}
|
||||
func (r *accessRepo) ListPositions(ctx context.Context, page, size int, q *biz.Position) ([]*biz.Position, int64, error) {
|
||||
func (r *organizationRepo) ListPositions(ctx context.Context, page, size int, q *biz.Position) ([]*biz.Position, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
|
@ -1103,12 +863,12 @@ func (r *accessRepo) ListPositions(ctx context.Context, page, size int, q *biz.P
|
|||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (r *accessRepo) PositionUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
func (r *organizationRepo) PositionUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := r.data.gormDB.WithContext(ctx).Model(&userPositionPO{}).Where("sys_position_id = ?", id).Pluck("sys_user_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
func (r *accessRepo) SetPositionUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
func (r *organizationRepo) SetPositionUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("sys_position_id = ?", id).Delete(&userPositionPO{}).Error; err != nil {
|
||||
return err
|
||||
|
|
@ -1123,7 +883,7 @@ func (r *accessRepo) SetPositionUsers(ctx context.Context, id uint, ids []uint)
|
|||
return nil
|
||||
})
|
||||
}
|
||||
func (r *accessRepo) SetUserPositions(ctx context.Context, uid uint, ids []uint) error {
|
||||
func (r *organizationRepo) SetUserPositions(ctx context.Context, uid uint, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("sys_user_id = ?", uid).Delete(&userPositionPO{}).Error; err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"kra/internal/conf"
|
||||
)
|
||||
|
||||
var ProviderSet = wire.NewSet(NewData, NewSystemRepo, NewAccessRepo, NewSettingsRepo, NewVersionRepo, NewExportRepo, NewAuditRepo, NewTaskRepo, NewMediaRepo, NewAnnouncementRepo, NewEmailRepo, NewCache, NewFileStorage)
|
||||
var ProviderSet = wire.NewSet(NewData, NewSystemRepo, NewAccessRepo, NewMenuRepo, NewOrganizationRepo, NewSettingsRepo, NewVersionRepo, NewExportRepo, NewAuditRepo, NewTaskRepo, NewMediaRepo, NewAnnouncementRepo, NewEmailRepo, NewCache, NewFileStorage)
|
||||
|
||||
type Data struct {
|
||||
mu sync.RWMutex
|
||||
|
|
|
|||
|
|
@ -0,0 +1,275 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"kra/internal/biz"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type menuRepo struct{ data *Data }
|
||||
|
||||
func NewMenuRepo(data *Data) biz.MenuRepo { return &menuRepo{data: data} }
|
||||
|
||||
func menuFromPO(po menuPO) *biz.Menu {
|
||||
return &biz.Menu{ID: po.ID, ParentID: po.ParentID, Path: po.Path, Name: po.Name, Hidden: po.Hidden, Component: po.Component, Sort: po.Sort, ActiveName: po.ActiveName, KeepAlive: po.KeepAlive, DefaultMenu: po.DefaultMenu, Title: po.Title, Icon: po.Icon, CloseTab: po.CloseTab, TransitionType: po.TransitionType}
|
||||
}
|
||||
|
||||
func menuToPO(v *biz.Menu) menuPO {
|
||||
return menuPO{ID: v.ID, ParentID: v.ParentID, Path: v.Path, Name: v.Name, Hidden: v.Hidden, Component: v.Component, Sort: v.Sort, ActiveName: v.ActiveName, KeepAlive: v.KeepAlive, DefaultMenu: v.DefaultMenu, Title: v.Title, Icon: v.Icon, CloseTab: v.CloseTab, TransitionType: v.TransitionType}
|
||||
}
|
||||
|
||||
func replaceMenuRelations(tx *gorm.DB, menu *biz.Menu) error {
|
||||
var oldButtonIDs []uint
|
||||
if err := tx.Model(&menuButtonPO{}).Where("sys_base_menu_id = ?", menu.ID).Pluck("id", &oldButtonIDs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if len(oldButtonIDs) > 0 {
|
||||
if err := tx.Where("sys_base_menu_btn_id IN ?", oldButtonIDs).Delete(&authorityButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", menu.ID).Delete(&menuButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", menu.ID).Delete(&menuParameterPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
buttons := make([]menuButtonPO, 0, len(menu.Buttons))
|
||||
for _, button := range menu.Buttons {
|
||||
buttons = append(buttons, menuButtonPO{Name: button.Name, Description: button.Description, MenuID: menu.ID})
|
||||
}
|
||||
if len(buttons) > 0 {
|
||||
if err := tx.Create(&buttons).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
parameters := make([]menuParameterPO, 0, len(menu.Parameters))
|
||||
for _, parameter := range menu.Parameters {
|
||||
parameters = append(parameters, menuParameterPO{MenuID: menu.ID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
|
||||
}
|
||||
if len(parameters) > 0 {
|
||||
return tx.Create(¶meters).Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *menuRepo) Create(ctx context.Context, v *biz.Menu) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var count int64
|
||||
if err := tx.Model(&menuPO{}).Where("name = ?", v.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("存在重复name,请修改name")
|
||||
}
|
||||
if v.ParentID != 0 {
|
||||
var parent menuPO
|
||||
if err := tx.First(&parent, v.ParentID).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New("父菜单不存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := tx.Model(&menuPO{}).Where("parent_id = ?", v.ParentID).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
if err := tx.Model(&authorityPO{}).Where("default_router = ?", parent.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("父菜单已被其他角色的首页占用,请先释放父菜单的首页权限")
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", v.ParentID).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
po := menuToPO(v)
|
||||
if err := tx.Create(&po).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
v.ID = po.ID
|
||||
return replaceMenuRelations(tx, v)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *menuRepo) Update(ctx context.Context, v *biz.Menu) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var old menuPO
|
||||
if err := tx.First(&old, v.ID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
var count int64
|
||||
if old.Name != v.Name {
|
||||
if err := tx.Model(&menuPO{}).Where("id <> ? AND name = ?", v.ID, v.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("存在相同name修改失败")
|
||||
}
|
||||
}
|
||||
if err := replaceMenuRelations(tx, v); err != nil {
|
||||
return err
|
||||
}
|
||||
values := map[string]any{"parent_id": v.ParentID, "path": v.Path, "name": v.Name, "hidden": v.Hidden, "component": v.Component, "sort": v.Sort, "active_name": v.ActiveName, "keep_alive": v.KeepAlive, "default_menu": v.DefaultMenu, "title": v.Title, "icon": v.Icon, "close_tab": v.CloseTab, "transition_type": v.TransitionType}
|
||||
return tx.Model(&old).Updates(values).Error
|
||||
})
|
||||
}
|
||||
|
||||
func (r *menuRepo) Delete(ctx context.Context, id uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var count int64
|
||||
if err := tx.Model(&menuPO{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("此菜单存在子菜单不可删除")
|
||||
}
|
||||
var menu menuPO
|
||||
if err := tx.First(&menu, id).Error; err != nil {
|
||||
return errors.New("记录不存在")
|
||||
}
|
||||
if err := tx.Model(&authorityPO{}).Where("default_router = ?", menu.Name).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("此菜单有角色正在作为首页,不可删除")
|
||||
}
|
||||
var buttonIDs []uint
|
||||
if err := tx.Model(&menuButtonPO{}).Where("sys_base_menu_id = ?", id).Pluck("id", &buttonIDs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_menu_id = ?", id).Delete(&authorityButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&menuButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&menuParameterPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Delete(&menuPO{}, id).Error
|
||||
})
|
||||
}
|
||||
|
||||
func (r *menuRepo) loadRelations(ctx context.Context, menu *biz.Menu) error {
|
||||
var parameters []menuParameterPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id = ?", menu.ID).Order("id").Find(¶meters).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
menu.Parameters = make([]*biz.MenuParameter, 0, len(parameters))
|
||||
for _, parameter := range parameters {
|
||||
menu.Parameters = append(menu.Parameters, &biz.MenuParameter{ID: parameter.ID, MenuID: parameter.MenuID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
|
||||
}
|
||||
var buttons []menuButtonPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id = ?", menu.ID).Order("id").Find(&buttons).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
menu.Buttons = make([]*biz.MenuButton, 0, len(buttons))
|
||||
for _, button := range buttons {
|
||||
menu.Buttons = append(menu.Buttons, &biz.MenuButton{ID: button.ID, Name: button.Name, Description: button.Description, MenuID: button.MenuID})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *menuRepo) Find(ctx context.Context, id uint) (*biz.Menu, error) {
|
||||
var po menuPO
|
||||
if err := r.data.gormDB.WithContext(ctx).First(&po, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
menu := menuFromPO(po)
|
||||
if err := r.loadRelations(ctx, menu); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menu, nil
|
||||
}
|
||||
|
||||
func (r *menuRepo) List(ctx context.Context) ([]*biz.Menu, error) {
|
||||
var pos []menuPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Order("sort,id").Find(&pos).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]*biz.Menu, 0, len(pos))
|
||||
for _, po := range pos {
|
||||
out = append(out, menuFromPO(po))
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
byID := make(map[uint]*biz.Menu, len(out))
|
||||
ids := make([]uint, 0, len(out))
|
||||
for _, menu := range out {
|
||||
byID[menu.ID] = menu
|
||||
ids = append(ids, menu.ID)
|
||||
menu.Parameters = []*biz.MenuParameter{}
|
||||
menu.Buttons = []*biz.MenuButton{}
|
||||
}
|
||||
var parameters []menuParameterPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id IN ?", ids).Order("id").Find(¶meters).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, parameter := range parameters {
|
||||
menu := byID[parameter.MenuID]
|
||||
menu.Parameters = append(menu.Parameters, &biz.MenuParameter{ID: parameter.ID, MenuID: parameter.MenuID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
|
||||
}
|
||||
var buttons []menuButtonPO
|
||||
if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id IN ?", ids).Order("id").Find(&buttons).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, button := range buttons {
|
||||
menu := byID[button.MenuID]
|
||||
menu.Buttons = append(menu.Buttons, &biz.MenuButton{ID: button.ID, Name: button.Name, Description: button.Description, MenuID: button.MenuID})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r *menuRepo) SetAuthorityMenus(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("sys_authority_authority_id = ?", id).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
links := make([]authorityMenuPO, 0, len(ids))
|
||||
for _, menuID := range ids {
|
||||
links = append(links, authorityMenuPO{SysAuthorityAuthorityID: id, SysBaseMenuID: menuID})
|
||||
}
|
||||
if len(links) > 0 {
|
||||
return tx.Create(&links).Error
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (r *menuRepo) AuthorityMenuIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := r.data.gormDB.WithContext(ctx).Model(&authorityMenuPO{}).Where("sys_authority_authority_id = ?", id).Pluck("sys_base_menu_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func (r *menuRepo) MenuRoleIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
var ids []uint
|
||||
err := r.data.gormDB.WithContext(ctx).Model(&authorityMenuPO{}).Where("sys_base_menu_id = ?", id).Pluck("sys_authority_authority_id", &ids).Error
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func (r *menuRepo) SetMenuRoles(ctx context.Context, id uint, ids []uint) error {
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("sys_base_menu_id = ?", id).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
links := make([]authorityMenuPO, 0, len(ids))
|
||||
for _, authorityID := range ids {
|
||||
links = append(links, authorityMenuPO{SysAuthorityAuthorityID: authorityID, SysBaseMenuID: id})
|
||||
}
|
||||
if len(links) > 0 {
|
||||
return tx.Create(&links).Error
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerAccessRoutes(group *gin.RouterGroup, engine *gin.Engine, svc *service.AccessService) {
|
||||
registerAuthorityRoutes(group, svc)
|
||||
registerMenuRoutes(group, svc)
|
||||
registerAPIRoutes(group, engine, svc)
|
||||
registerPolicyRoutes(group, svc)
|
||||
registerDepartmentRoutes(group, svc)
|
||||
registerPositionRoutes(group, svc)
|
||||
}
|
||||
|
||||
func accessControl(svc *service.AccessService, audit *service.AuditService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
claims := currentClaims(c)
|
||||
if claims == nil {
|
||||
noAuth(c, "未登录或非法访问")
|
||||
return
|
||||
}
|
||||
path := c.Request.URL.Path
|
||||
allowed, err := svc.Authorize(c.Request.Context(), claims.AuthorityID, path, c.Request.Method)
|
||||
if err != nil || !allowed {
|
||||
requestID, _ := c.Get("request_id")
|
||||
_ = audit.RecordDataAccess(c.Request.Context(), &biz.DataAccessLog{EventType: "blocked_access", Operation: c.Request.Method, UserID: claims.ID, AuthorityID: claims.AuthorityID, RequestID: toString(requestID), Method: c.Request.Method, Path: c.Request.URL.Path, Detail: "Casbin policy denied the request"})
|
||||
c.AbortWithStatusJSON(http.StatusForbidden, response{Code: codeError, Data: nil, Msg: "权限不足"})
|
||||
return
|
||||
}
|
||||
scope, err := svc.ResolveDataScope(c.Request.Context(), claims.AuthorityID, claims.ID)
|
||||
if err != nil {
|
||||
fail(c, "数据权限加载失败")
|
||||
return
|
||||
}
|
||||
c.Request = c.Request.WithContext(biz.NewDataScopeContext(c.Request.Context(), scope))
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type announcementRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
UserID *uint `json:"userID"`
|
||||
Attachments json.RawMessage `json:"attachments"`
|
||||
}
|
||||
|
||||
func announcementInput(req announcementRequest) service.AnnouncementInput {
|
||||
return service.AnnouncementInput{ID: req.ID, Title: req.Title, Content: req.Content, UserID: req.UserID, Attachments: req.Attachments}
|
||||
}
|
||||
|
||||
func registerAnnouncementRoutes(private, public *gin.RouterGroup, svc *service.AnnouncementService) {
|
||||
privateInfo := private.Group("/info")
|
||||
privateInfo.POST("/createInfo", func(c *gin.Context) {
|
||||
var req announcementRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.Create(c.Request.Context(), announcementInput(req)); err != nil {
|
||||
fail(c, "创建失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{}, "创建成功")
|
||||
})
|
||||
privateInfo.DELETE("/deleteInfo", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
|
||||
if err := svc.Delete(c.Request.Context(), uint(id)); err != nil {
|
||||
fail(c, "删除失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{}, "删除成功")
|
||||
})
|
||||
privateInfo.DELETE("/deleteInfoByIds", func(c *gin.Context) {
|
||||
values := c.QueryArray("IDs[]")
|
||||
if len(values) == 0 {
|
||||
values = c.QueryArray("IDs")
|
||||
}
|
||||
ids := make([]uint, 0, len(values))
|
||||
for _, value := range values {
|
||||
id, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
ids = append(ids, uint(id))
|
||||
}
|
||||
if err := svc.DeleteByIDs(c.Request.Context(), ids); err != nil {
|
||||
fail(c, "批量删除失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{}, "批量删除成功")
|
||||
})
|
||||
privateInfo.PUT("/updateInfo", func(c *gin.Context) {
|
||||
var req announcementRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.Update(c.Request.Context(), announcementInput(req)); err != nil {
|
||||
fail(c, "更新失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{}, "更新成功")
|
||||
})
|
||||
privateInfo.GET("/findInfo", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
|
||||
item, err := svc.Find(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "查询失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
okWithData(c, item)
|
||||
})
|
||||
privateInfo.GET("/getInfoList", func(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
start, startErr := parseAnnouncementTime(c.Query("startCreatedAt"))
|
||||
end, endErr := parseAnnouncementTime(c.Query("endCreatedAt"))
|
||||
if startErr != nil || endErr != nil || (start == nil) != (end == nil) {
|
||||
fail(c, "创建日期范围不合法")
|
||||
return
|
||||
}
|
||||
items, total, err := svc.List(c.Request.Context(), page, pageSize, start, end)
|
||||
if err != nil {
|
||||
fail(c, "获取失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, pageResult{List: items, Total: total, Page: page, PageSize: pageSize}, "获取成功")
|
||||
})
|
||||
publicInfo := public.Group("/info")
|
||||
publicInfo.GET("/getInfoDataSource", func(c *gin.Context) {
|
||||
users, err := svc.UserOptions(c.Request.Context())
|
||||
if err != nil {
|
||||
fail(c, "查询失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
okWithData(c, gin.H{"userID": users})
|
||||
})
|
||||
publicInfo.GET("/getInfoPublic", func(c *gin.Context) {
|
||||
writeResult(c, codeSuccess, gin.H{"info": "不需要鉴权的公告接口信息"}, "获取成功")
|
||||
})
|
||||
}
|
||||
|
||||
func parseAnnouncementTime(value string) (*time.Time, error) {
|
||||
if value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &parsed, nil
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerAPIRoutes(group *gin.RouterGroup, engine *gin.Engine, svc *service.AccessService) {
|
||||
router := group.Group("/api")
|
||||
router.POST("/getApiList", func(c *gin.Context) {
|
||||
var req struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
APIGroup string `json:"apiGroup"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
items, total, err := svc.APIs(c.Request.Context(), req.Page, req.PageSize, &biz.API{Path: req.Path, Description: req.Description, APIGroup: req.APIGroup, Method: req.Method})
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, pageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
|
||||
})
|
||||
router.POST("/getAllApis", func(c *gin.Context) {
|
||||
items, _, err := svc.APIs(c.Request.Context(), 1, 10000, nil)
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"apis": items}, "获取成功")
|
||||
})
|
||||
type apiRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
APIGroup string `json:"apiGroup"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
router.POST("/createApi", func(c *gin.Context) {
|
||||
var req apiRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.CreateAPI(c.Request.Context(), &biz.API{Path: req.Path, Description: req.Description, APIGroup: req.APIGroup, Method: req.Method}); err != nil {
|
||||
fail(c, "创建失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/updateApi", func(c *gin.Context) {
|
||||
var req apiRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.UpdateAPI(c.Request.Context(), &biz.API{ID: req.ID, Path: req.Path, Description: req.Description, APIGroup: req.APIGroup, Method: req.Method}); err != nil {
|
||||
fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/deleteApi", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.DeleteAPIs(c.Request.Context(), []uint{req.ID}); err != nil {
|
||||
fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.DELETE("/deleteApisByIds", func(c *gin.Context) {
|
||||
var req struct {
|
||||
IDs []uint `json:"ids"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.DeleteAPIs(c.Request.Context(), req.IDs); err != nil {
|
||||
fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/getApiById", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
item, err := svc.API(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"api": item}, "获取成功")
|
||||
})
|
||||
router.GET("/getApiGroups", func(c *gin.Context) {
|
||||
items, _, err := svc.APIs(c.Request.Context(), 1, 10000, nil)
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
groups := []string{}
|
||||
for _, item := range items {
|
||||
value, _ := item["apiGroup"].(string)
|
||||
if value != "" && !seen[value] {
|
||||
seen[value] = true
|
||||
groups = append(groups, value)
|
||||
}
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"groups": groups}, "获取成功")
|
||||
})
|
||||
router.GET("/getApiRoles", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("apiId"), 10, 64)
|
||||
ids, err := svc.APIRoleIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, ids, "获取成功")
|
||||
})
|
||||
router.POST("/setApiRoles", func(c *gin.Context) {
|
||||
var req struct {
|
||||
APIID uint `json:"apiId"`
|
||||
AuthorityIDs []uint `json:"authorityIds"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetAPIRoles(c.Request.Context(), req.APIID, req.AuthorityIDs); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.GET("/syncApi", func(c *gin.Context) {
|
||||
routes := engine.Routes()
|
||||
items := make([]*biz.API, 0, len(routes))
|
||||
for _, route := range routes {
|
||||
items = append(items, &biz.API{Path: route.Path, Method: route.Method})
|
||||
}
|
||||
result, err := svc.SyncAPIs(c.Request.Context(), items)
|
||||
if err != nil {
|
||||
fail(c, "同步检查失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, result, "获取成功")
|
||||
})
|
||||
router.POST("/ignoreApi", func(c *gin.Context) {
|
||||
var req struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
Flag bool `json:"flag"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil || req.Path == "" || req.Method == "" {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetAPIIgnored(c.Request.Context(), req.Path, req.Method, req.Flag); err != nil {
|
||||
fail(c, "忽略设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/enterSyncApi", func(c *gin.Context) {
|
||||
var req struct {
|
||||
NewAPIs []apiRequest `json:"newApis"`
|
||||
DeleteAPIs []apiRequest `json:"deleteApis"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
toDomain := func(values []apiRequest) []*biz.API {
|
||||
items := make([]*biz.API, 0, len(values))
|
||||
for _, value := range values {
|
||||
items = append(items, &biz.API{ID: value.ID, Path: value.Path, Description: value.Description, APIGroup: value.APIGroup, Method: value.Method})
|
||||
}
|
||||
return items
|
||||
}
|
||||
if err := svc.ApplyAPISync(c.Request.Context(), toDomain(req.NewAPIs), toDomain(req.DeleteAPIs)); err != nil {
|
||||
fail(c, "同步失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.GET("/freshCasbin", func(c *gin.Context) { ok(c) })
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerAuthorityRoutes(group *gin.RouterGroup, svc *service.AccessService) {
|
||||
router := group.Group("/authority")
|
||||
router.POST("/getAuthorityList", func(c *gin.Context) {
|
||||
items, err := svc.Authorities(c.Request.Context())
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, items, "获取成功")
|
||||
})
|
||||
type authorityRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
AuthorityName string `json:"authorityName"`
|
||||
ParentID *uint `json:"parentId"`
|
||||
DataScope int `json:"dataScope"`
|
||||
DefaultRouter string `json:"defaultRouter"`
|
||||
}
|
||||
router.POST("/createAuthority", func(c *gin.Context) {
|
||||
var req authorityRequest
|
||||
if c.ShouldBindJSON(&req) != nil || req.AuthorityID == 0 {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
value := &biz.Authority{AuthorityID: req.AuthorityID, AuthorityName: req.AuthorityName, ParentID: req.ParentID, DataScope: req.DataScope, DefaultRouter: req.DefaultRouter}
|
||||
if err := svc.CreateAuthority(c.Request.Context(), value); err != nil {
|
||||
fail(c, "创建失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"authority": gin.H{"authorityId": value.AuthorityID, "authorityName": value.AuthorityName, "parentId": value.ParentID, "dataScope": value.DataScope, "defaultRouter": value.DefaultRouter}}, "创建成功")
|
||||
})
|
||||
router.POST("/copyAuthority", func(c *gin.Context) {
|
||||
var req struct {
|
||||
Authority authorityRequest `json:"authority"`
|
||||
OldAuthorityID uint `json:"oldAuthorityId"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil || req.Authority.AuthorityID == 0 || req.OldAuthorityID == 0 {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
value := &biz.Authority{AuthorityID: req.Authority.AuthorityID, AuthorityName: req.Authority.AuthorityName, ParentID: req.Authority.ParentID, DataScope: req.Authority.DataScope, DefaultRouter: req.Authority.DefaultRouter}
|
||||
if err := svc.CopyAuthority(c.Request.Context(), req.OldAuthorityID, value); err != nil {
|
||||
fail(c, "拷贝失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"authority": gin.H{"authorityId": value.AuthorityID, "authorityName": value.AuthorityName, "parentId": value.ParentID, "dataScope": value.DataScope, "defaultRouter": value.DefaultRouter}}, "拷贝成功")
|
||||
})
|
||||
router.PUT("/updateAuthority", func(c *gin.Context) {
|
||||
var req authorityRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
value := &biz.Authority{AuthorityID: req.AuthorityID, AuthorityName: req.AuthorityName, ParentID: req.ParentID, DataScope: req.DataScope, DefaultRouter: req.DefaultRouter}
|
||||
if err := svc.UpdateAuthority(c.Request.Context(), value); err != nil {
|
||||
fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"authority": gin.H{"authorityId": value.AuthorityID, "authorityName": value.AuthorityName, "parentId": value.ParentID, "dataScope": value.DataScope, "defaultRouter": value.DefaultRouter}}, "更新成功")
|
||||
})
|
||||
router.POST("/deleteAuthority", func(c *gin.Context) {
|
||||
var req struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.DeleteAuthority(c.Request.Context(), req.AuthorityID); err != nil {
|
||||
fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/setRoleUsers", func(c *gin.Context) {
|
||||
var req struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
UserIDs []uint `json:"userIds"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetAuthorityUsers(c.Request.Context(), req.AuthorityID, req.UserIDs); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.GET("/getUsersByAuthority", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("authorityId"), 10, 64)
|
||||
ids, err := svc.AuthorityUserIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, ids, "获取成功")
|
||||
})
|
||||
router.POST("/setDataScope", func(c *gin.Context) {
|
||||
var req struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
DataScope int `json:"dataScope"`
|
||||
DepartmentIDs []uint `json:"deptIds"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetDataScope(c.Request.Context(), req.AuthorityID, req.DataScope, req.DepartmentIDs); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.GET("/getDataScopeDepts", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("authorityId"), 10, 64)
|
||||
ids, err := svc.DataScopeDepartmentIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, ids, "获取成功")
|
||||
})
|
||||
}
|
||||
|
|
@ -13,33 +13,6 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerEmailRoutes(group *gin.RouterGroup, svc *service.EmailService) {
|
||||
email := group.Group("/email")
|
||||
email.POST("/emailTest", func(c *gin.Context) {
|
||||
if err := svc.Test(c.Request.Context()); err != nil {
|
||||
fail(c, "发送失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{}, "发送成功")
|
||||
})
|
||||
email.POST("/sendEmail", func(c *gin.Context) {
|
||||
var req struct {
|
||||
To string `json:"to"`
|
||||
Subject string `json:"subject"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.Send(c.Request.Context(), req.To, req.Subject, req.Body); err != nil {
|
||||
fail(c, "发送失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{}, "发送成功")
|
||||
})
|
||||
}
|
||||
|
||||
func emailErrorAlert(svc *service.EmailService, logger *slog.Logger) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if strings.Contains(c.Request.URL.Path, "/email/") {
|
||||
|
|
|
|||
|
|
@ -13,11 +13,14 @@ import (
|
|||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/conf"
|
||||
"kra/internal/server/handler"
|
||||
servermiddleware "kra/internal/server/middleware"
|
||||
serverrouter "kra/internal/server/router"
|
||||
"kra/internal/service"
|
||||
"kra/internal/worker"
|
||||
"kra/pkg/adminauth"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
|
|
@ -30,10 +33,10 @@ type GinServer struct {
|
|||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewGinServer(c *conf.Server, config *conf.AdminBackend, svc *service.SystemService, access *service.AccessService, settings *service.SettingsService, versions *service.VersionService, exports *service.ExportService, audit *service.AuditService, tasks *service.TaskService, media *service.MediaService, announcements *service.AnnouncementService, emails *service.EmailService, scheduler *TaskScheduler, logger *slog.Logger) *GinServer {
|
||||
func NewGinServer(c *conf.Server, config *conf.AdminBackend, svc *service.SystemService, access *service.AccessService, authority *handler.Authority, menu *handler.Menu, api *handler.API, permission *handler.Permission, organization *handler.Organization, announcement *handler.Announcement, email *handler.Email, task *handler.Task, settings *service.SettingsService, versions *service.VersionService, exports *service.ExportService, audit *service.AuditService, media *service.MediaService, emails *service.EmailService, scheduler *worker.TaskScheduler, logger *slog.Logger) *GinServer {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
engine := gin.New()
|
||||
engine.Use(ginRequestMeta(), emailErrorAlert(emails, logger), gin.Recovery(), securityRateLimit(svc, settings), operationAudit(audit))
|
||||
engine.Use(servermiddleware.RequestMeta(), emailErrorAlert(emails, logger), gin.Recovery(), securityRateLimit(svc, settings), operationAudit(audit))
|
||||
prefix := ""
|
||||
if config != nil {
|
||||
prefix = strings.TrimSuffix(config.RouterPrefix, "/")
|
||||
|
|
@ -44,18 +47,22 @@ func NewGinServer(c *conf.Server, config *conf.AdminBackend, svc *service.System
|
|||
})
|
||||
registerPublicRoutes(public, engine, config, svc, settings, access, audit, scheduler)
|
||||
private := engine.Group(prefix)
|
||||
private.Use(jwtAuth(config, settings), mustChangePasswordGuard(), accessControl(access, audit))
|
||||
private.Use(servermiddleware.Auth(config, settings), servermiddleware.MustChangePassword(), servermiddleware.AccessControl(access, audit))
|
||||
registerPrivateRoutes(private, svc, settings)
|
||||
registerAccessRoutes(private, engine, access)
|
||||
serverrouter.RegisterAuthority(private, authority)
|
||||
serverrouter.RegisterMenu(private, menu)
|
||||
serverrouter.RegisterAPI(private, engine, api)
|
||||
serverrouter.RegisterPermission(private, permission)
|
||||
serverrouter.RegisterOrganization(private, organization)
|
||||
registerSettingsRoutes(private, public, settings)
|
||||
registerSystemConfigRoutes(private, config, svc, settings, scheduler)
|
||||
registerVersionRoutes(private, versions)
|
||||
registerExportRoutes(private, public, svc, exports)
|
||||
registerAuditRoutes(private, public, audit)
|
||||
registerTaskRoutes(private, tasks, scheduler)
|
||||
serverrouter.RegisterTask(private, task)
|
||||
registerMediaRoutes(private, media)
|
||||
registerAnnouncementRoutes(private, public, announcements)
|
||||
registerEmailRoutes(private, emails)
|
||||
serverrouter.RegisterAnnouncement(private, public, announcement)
|
||||
serverrouter.RegisterEmail(private, email)
|
||||
|
||||
engine.NoRoute(func(c *gin.Context) {
|
||||
if serveLocalStorage(c, config) {
|
||||
|
|
@ -100,74 +107,9 @@ func serveLocalStorage(c *gin.Context, config *conf.AdminBackend) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func jwtAuth(config *conf.AdminBackend, settings *service.SettingsService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
token := c.GetHeader("x-token")
|
||||
if token == "" {
|
||||
token, _ = c.Cookie("x-token")
|
||||
}
|
||||
secret := ""
|
||||
if config != nil && config.Jwt != nil {
|
||||
secret = config.Jwt.SigningKey
|
||||
}
|
||||
claims, err := adminauth.Parse(token, secret)
|
||||
if err != nil {
|
||||
noAuth(c, "未登录或非法访问")
|
||||
return
|
||||
}
|
||||
if disabled, checkErr := settings.IsTokenDisabled(c.Request.Context(), token); checkErr != nil || disabled {
|
||||
noAuth(c, "登录状态已失效")
|
||||
return
|
||||
}
|
||||
if claims.ExpiresAt != nil && claims.BufferTime > 0 && time.Until(claims.ExpiresAt.Time) < time.Duration(claims.BufferTime)*time.Second {
|
||||
expires, buffer := 7*24*time.Hour, time.Duration(claims.BufferTime)*time.Second
|
||||
issuer := claims.Issuer
|
||||
if config != nil && config.Jwt != nil {
|
||||
if config.Jwt.ExpiresTime != nil {
|
||||
expires = config.Jwt.ExpiresTime.AsDuration()
|
||||
}
|
||||
if config.Jwt.BufferTime != nil {
|
||||
buffer = config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
if config.Jwt.Issuer != "" {
|
||||
issuer = config.Jwt.Issuer
|
||||
}
|
||||
}
|
||||
newToken, newClaims, refreshErr := adminauth.Generate(secret, issuer, expires, buffer, claims.ID, claims.AuthorityID, claims.UUID, claims.Username, claims.NickName, claims.MustChangePwd)
|
||||
if refreshErr == nil {
|
||||
c.Header("new-token", newToken)
|
||||
c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt.Unix(), 10))
|
||||
http.SetCookie(c.Writer, &http.Cookie{Name: "x-token", Value: newToken, Path: "/", MaxAge: int(expires.Seconds()), HttpOnly: true, SameSite: http.SameSiteStrictMode})
|
||||
}
|
||||
}
|
||||
c.Set("admin_claims", claims)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
func currentClaims(c *gin.Context) *adminauth.Claims { return servermiddleware.Claims(c) }
|
||||
|
||||
func currentClaims(c *gin.Context) *adminauth.Claims {
|
||||
claims, _ := c.Get("admin_claims")
|
||||
result, _ := claims.(*adminauth.Claims)
|
||||
return result
|
||||
}
|
||||
|
||||
func mustChangePasswordGuard() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
claims := currentClaims(c)
|
||||
if claims == nil || !claims.MustChangePwd {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
path := strings.TrimSuffix(c.Request.URL.Path, "/")
|
||||
if strings.HasSuffix(path, "/user/changePassword") || strings.HasSuffix(path, "/user/getUserInfo") || strings.HasSuffix(path, "/jwt/jsonInBlacklist") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
c.AbortWithStatusJSON(http.StatusConflict, response{Code: codePasswordChangeRequired, Data: gin.H{"needChangePassword": true}, Msg: "请先修改初始密码"})
|
||||
}
|
||||
}
|
||||
|
||||
func registerPublicRoutes(group *gin.RouterGroup, engine *gin.Engine, config *conf.AdminBackend, svc *service.SystemService, settings *service.SettingsService, access *service.AccessService, audit *service.AuditService, scheduler *TaskScheduler) {
|
||||
func registerPublicRoutes(group *gin.RouterGroup, engine *gin.Engine, config *conf.AdminBackend, svc *service.SystemService, settings *service.SettingsService, access *service.AccessService, audit *service.AuditService, scheduler *worker.TaskScheduler) {
|
||||
expiration := 3 * time.Minute
|
||||
keyLong, width, height := 6, 240, 80
|
||||
if config != nil && config.Captcha != nil {
|
||||
|
|
@ -644,15 +586,3 @@ func (s *GinServer) Stop(ctx context.Context) error {
|
|||
s.logger.InfoContext(ctx, "Gin HTTP server stopping")
|
||||
return s.server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func ginRequestMeta() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
requestID := c.GetHeader("X-Request-Id")
|
||||
if requestID == "" {
|
||||
requestID = uuid.NewString()
|
||||
}
|
||||
c.Header("X-Request-Id", requestID)
|
||||
c.Set("request_id", requestID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Announcement struct{ service *service.AnnouncementService }
|
||||
|
||||
func NewAnnouncement(service *service.AnnouncementService) *Announcement {
|
||||
return &Announcement{service: service}
|
||||
}
|
||||
|
||||
func announcementInput(req dto.AnnouncementRequest) service.AnnouncementInput {
|
||||
return service.AnnouncementInput{ID: req.ID, Title: req.Title, Content: req.Content, UserID: req.UserID, Attachments: req.Attachments}
|
||||
}
|
||||
|
||||
func (h *Announcement) Create(c *gin.Context) {
|
||||
var req dto.AnnouncementRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.Create(c.Request.Context(), announcementInput(req)); err != nil {
|
||||
httpx.Fail(c, "创建失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "创建成功")
|
||||
}
|
||||
|
||||
func (h *Announcement) Delete(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
|
||||
if err := h.service.Delete(c.Request.Context(), uint(id)); err != nil {
|
||||
httpx.Fail(c, "删除失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "删除成功")
|
||||
}
|
||||
|
||||
func (h *Announcement) DeleteByIDs(c *gin.Context) {
|
||||
values := c.QueryArray("IDs[]")
|
||||
if len(values) == 0 {
|
||||
values = c.QueryArray("IDs")
|
||||
}
|
||||
ids := make([]uint, 0, len(values))
|
||||
for _, value := range values {
|
||||
id, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
ids = append(ids, uint(id))
|
||||
}
|
||||
if err := h.service.DeleteByIDs(c.Request.Context(), ids); err != nil {
|
||||
httpx.Fail(c, "批量删除失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "批量删除成功")
|
||||
}
|
||||
|
||||
func (h *Announcement) Update(c *gin.Context) {
|
||||
var req dto.AnnouncementRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.Update(c.Request.Context(), announcementInput(req)); err != nil {
|
||||
httpx.Fail(c, "更新失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "更新成功")
|
||||
}
|
||||
|
||||
func (h *Announcement) Find(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
|
||||
item, err := h.service.Find(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "查询失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OKWithData(c, item)
|
||||
}
|
||||
|
||||
func (h *Announcement) List(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
start, startErr := parseTime(c.Query("startCreatedAt"))
|
||||
end, endErr := parseTime(c.Query("endCreatedAt"))
|
||||
if startErr != nil || endErr != nil || (start == nil) != (end == nil) {
|
||||
httpx.Fail(c, "创建日期范围不合法")
|
||||
return
|
||||
}
|
||||
items, total, err := h.service.List(c.Request.Context(), page, pageSize, start, end)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: page, PageSize: pageSize}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Announcement) DataSource(c *gin.Context) {
|
||||
users, err := h.service.UserOptions(c.Request.Context())
|
||||
if err != nil {
|
||||
httpx.Fail(c, "查询失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OKWithData(c, gin.H{"userID": users})
|
||||
}
|
||||
|
||||
func (h *Announcement) Public(c *gin.Context) {
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"info": "不需要鉴权的公告接口信息"}, "获取成功")
|
||||
}
|
||||
|
||||
func parseTime(value string) (*time.Time, error) {
|
||||
if value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &parsed, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type API struct{ service *service.AccessService }
|
||||
|
||||
func NewAPI(service *service.AccessService) *API { return &API{service: service} }
|
||||
|
||||
func (h *API) List(c *gin.Context) {
|
||||
var req dto.APIListRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
items, total, err := h.service.ListAPI(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
|
||||
}
|
||||
func (h *API) All(c *gin.Context) {
|
||||
items, err := h.service.AllAPI(c.Request.Context())
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"apis": items}, "获取成功")
|
||||
}
|
||||
func (h *API) Create(c *gin.Context) {
|
||||
var req dto.APIRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.CreateAPIRequest(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "创建失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) Update(c *gin.Context) {
|
||||
var req dto.APIRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.UpdateAPIRequest(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) Delete(c *gin.Context) {
|
||||
var req dto.DeleteAPIRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.DeleteAPIs(c.Request.Context(), []uint{req.ID}); err != nil {
|
||||
httpx.Fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) DeleteByIDs(c *gin.Context) {
|
||||
var req dto.DeleteAPIsRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.DeleteAPIs(c.Request.Context(), req.IDs); err != nil {
|
||||
httpx.Fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) Find(c *gin.Context) {
|
||||
var req dto.GetAPIRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
item, err := h.service.FindAPIResponse(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"api": item}, "获取成功")
|
||||
}
|
||||
func (h *API) Groups(c *gin.Context) {
|
||||
items, err := h.service.AllAPI(c.Request.Context())
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
groups := []string{}
|
||||
for _, item := range items {
|
||||
if item.APIGroup != "" && !seen[item.APIGroup] {
|
||||
seen[item.APIGroup] = true
|
||||
groups = append(groups, item.APIGroup)
|
||||
}
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"groups": groups}, "获取成功")
|
||||
}
|
||||
func (h *API) Roles(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("apiId"), 10, 64)
|
||||
ids, err := h.service.APIRoleIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, ids, "获取成功")
|
||||
}
|
||||
func (h *API) SetRoles(c *gin.Context) {
|
||||
var req dto.SetAPIRolesRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetAPIRoles(c.Request.Context(), req.APIID, req.AuthorityIDs); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) Sync(engine *gin.Engine) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
routes := engine.Routes()
|
||||
values := make([]dto.APIRequest, 0, len(routes))
|
||||
for _, route := range routes {
|
||||
values = append(values, dto.APIRequest{Path: route.Path, Method: route.Method})
|
||||
}
|
||||
result, err := h.service.SyncAPIResponses(c.Request.Context(), values)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "同步检查失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, result, "获取成功")
|
||||
}
|
||||
}
|
||||
func (h *API) Ignore(c *gin.Context) {
|
||||
var req dto.IgnoreAPIRequest
|
||||
if c.ShouldBindJSON(&req) != nil || req.Path == "" || req.Method == "" {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetAPIIgnored(c.Request.Context(), req.Path, req.Method, req.Flag); err != nil {
|
||||
httpx.Fail(c, "忽略设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) ApplySync(c *gin.Context) {
|
||||
var req dto.ApplyAPISyncRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.ApplyAPISyncRequest(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "同步失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) FreshCasbin(c *gin.Context) { httpx.OK(c) }
|
||||
|
||||
func (h *API) SetPolicyPaths(c *gin.Context) {
|
||||
var req dto.SetPolicyPathsRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetPolicyPathsRequest(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *API) PolicyPaths(c *gin.Context) {
|
||||
var req dto.GetPolicyPathsRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
paths, err := h.service.PolicyPathResponses(c.Request.Context(), req.AuthorityID)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"paths": paths}, "获取成功")
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Authority struct{ service *service.AccessService }
|
||||
|
||||
func NewAuthority(service *service.AccessService) *Authority { return &Authority{service: service} }
|
||||
|
||||
func (h *Authority) List(c *gin.Context) {
|
||||
items, err := h.service.Authorities(c.Request.Context())
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, items, "获取成功")
|
||||
}
|
||||
func (h *Authority) Create(c *gin.Context) {
|
||||
var req dto.AuthorityRequest
|
||||
if c.ShouldBindJSON(&req) != nil || req.AuthorityID == 0 {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
value, err := h.service.CreateAuthorityRequest(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "创建失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"authority": value}, "创建成功")
|
||||
}
|
||||
func (h *Authority) Copy(c *gin.Context) {
|
||||
var req dto.CopyAuthorityRequest
|
||||
if c.ShouldBindJSON(&req) != nil || req.Authority.AuthorityID == 0 || req.OldAuthorityID == 0 {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
value, err := h.service.CopyAuthorityRequest(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "拷贝失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"authority": value}, "拷贝成功")
|
||||
}
|
||||
func (h *Authority) Update(c *gin.Context) {
|
||||
var req dto.AuthorityRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
value, err := h.service.UpdateAuthorityRequest(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"authority": value}, "更新成功")
|
||||
}
|
||||
func (h *Authority) Delete(c *gin.Context) {
|
||||
var req dto.DeleteAuthorityRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.DeleteAuthority(c.Request.Context(), req.AuthorityID); err != nil {
|
||||
httpx.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Authority) SetUsers(c *gin.Context) {
|
||||
var req dto.SetRoleUsersRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetAuthorityUsers(c.Request.Context(), req.AuthorityID, req.UserIDs); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Authority) Users(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("authorityId"), 10, 64)
|
||||
ids, err := h.service.AuthorityUserIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, ids, "获取成功")
|
||||
}
|
||||
func (h *Authority) SetDataScope(c *gin.Context) {
|
||||
var req dto.SetDataScopeRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetDataScope(c.Request.Context(), req.AuthorityID, req.DataScope, req.DepartmentIDs); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Authority) DataScopeDepartments(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("authorityId"), 10, 64)
|
||||
ids, err := h.service.DataScopeDepartmentIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, ids, "获取成功")
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Email struct{ service *service.EmailService }
|
||||
|
||||
func NewEmail(service *service.EmailService) *Email { return &Email{service: service} }
|
||||
|
||||
func (h *Email) Test(c *gin.Context) {
|
||||
if err := h.service.Test(c.Request.Context()); err != nil {
|
||||
httpx.Fail(c, "发送失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "发送成功")
|
||||
}
|
||||
|
||||
func (h *Email) Send(c *gin.Context) {
|
||||
var req dto.SendEmailRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.Send(c.Request.Context(), req.To, req.Subject, req.Body); err != nil {
|
||||
httpx.Fail(c, "发送失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "发送成功")
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Menu struct{ service *service.MenuService }
|
||||
|
||||
func NewMenu(service *service.MenuService) *Menu { return &Menu{service: service} }
|
||||
|
||||
func (h *Menu) List(c *gin.Context) {
|
||||
items, err := h.service.List(c.Request.Context())
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: int64(len(items)), Page: 1, PageSize: 999}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Menu) Tree(c *gin.Context) {
|
||||
items, err := h.service.Tree(c.Request.Context())
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"menus": items}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Menu) Create(c *gin.Context) {
|
||||
var req dto.MenuRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.Create(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "新增失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Menu) Update(c *gin.Context) {
|
||||
var req dto.MenuRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.Update(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Menu) Delete(c *gin.Context) {
|
||||
var req dto.DeleteMenuRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.Delete(c.Request.Context(), req.ID); err != nil {
|
||||
httpx.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Menu) Find(c *gin.Context) {
|
||||
var req dto.GetMenuRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
item, err := h.service.Find(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"menu": item}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Menu) SetAuthorityMenus(c *gin.Context) {
|
||||
var req dto.SetAuthorityMenusRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetAuthorityMenus(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "添加失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Menu) AuthorityMenus(c *gin.Context) {
|
||||
var req dto.GetAuthorityMenusRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
menus, err := h.service.AuthorityMenus(c.Request.Context(), req.AuthorityID)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"menus": menus}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Menu) RoleIDs(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("menuId"), 10, 64)
|
||||
ids, err := h.service.RoleIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, ids, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Menu) SetRoles(c *gin.Context) {
|
||||
var req dto.SetMenuRolesRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetRoles(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Organization struct{ service *service.OrganizationService }
|
||||
|
||||
func NewOrganization(service *service.OrganizationService) *Organization {
|
||||
return &Organization{service: service}
|
||||
}
|
||||
|
||||
func (h *Organization) ListDepartments(c *gin.Context) {
|
||||
var req dto.DepartmentListRequest
|
||||
_ = c.ShouldBindJSON(&req)
|
||||
items, err := h.service.Departments(c.Request.Context(), req.Name)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, items, "获取成功")
|
||||
}
|
||||
func (h *Organization) CreateDepartment(c *gin.Context) {
|
||||
var req dto.DepartmentRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.CreateDepartment(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "创建失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) UpdateDepartment(c *gin.Context) {
|
||||
var req dto.DepartmentRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.UpdateDepartment(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) DeleteDepartment(c *gin.Context) {
|
||||
var req dto.DeleteDepartmentRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.DeleteDepartment(c.Request.Context(), req.ID); err != nil {
|
||||
httpx.Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) FindDepartment(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("id"), 10, 64)
|
||||
item, err := h.service.Department(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, item, "获取成功")
|
||||
}
|
||||
func (h *Organization) DepartmentUsers(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("deptId"), 10, 64)
|
||||
ids, err := h.service.DepartmentUserIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, ids, "获取成功")
|
||||
}
|
||||
func (h *Organization) SetDepartmentUsers(c *gin.Context) {
|
||||
var req dto.SetDepartmentUsersRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetDepartmentUsers(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) SetUserDepartments(c *gin.Context) {
|
||||
var req dto.SetUserDepartmentsRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetUserDepartments(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Organization) ListPositions(c *gin.Context) {
|
||||
var req dto.PositionListRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
items, total, err := h.service.Positions(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
|
||||
}
|
||||
func (h *Organization) CreatePosition(c *gin.Context) {
|
||||
var req dto.PositionRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.CreatePosition(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "创建失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) UpdatePosition(c *gin.Context) {
|
||||
var req dto.PositionRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.UpdatePosition(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) DeletePosition(c *gin.Context) {
|
||||
var req dto.DeletePositionRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.DeletePosition(c.Request.Context(), req.ID); err != nil {
|
||||
httpx.Fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) FindPosition(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("id"), 10, 64)
|
||||
item, err := h.service.Position(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, item, "获取成功")
|
||||
}
|
||||
func (h *Organization) PositionUsers(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("positionId"), 10, 64)
|
||||
ids, err := h.service.PositionUserIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, ids, "获取成功")
|
||||
}
|
||||
func (h *Organization) SetPositionUsers(c *gin.Context) {
|
||||
var req dto.SetPositionUsersRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetPositionUsers(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
func (h *Organization) SetUserPositions(c *gin.Context) {
|
||||
var req dto.SetUserPositionsRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetUserPositions(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Permission struct{ service *service.AccessService }
|
||||
|
||||
func NewPermission(service *service.AccessService) *Permission { return &Permission{service: service} }
|
||||
|
||||
func (h *Permission) Buttons(c *gin.Context) {
|
||||
var req dto.GetAuthorityButtonsRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
selected, err := h.service.SelectedButtons(c.Request.Context(), req.AuthorityID, req.MenuID)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "查询失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"selected": selected}, "查询成功")
|
||||
}
|
||||
|
||||
func (h *Permission) SetButtons(c *gin.Context) {
|
||||
var req dto.SetAuthorityButtonsRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.SetSelectedButtons(c.Request.Context(), req.AuthorityID, req.MenuID, req.Selected); err != nil {
|
||||
httpx.Fail(c, "分配失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Permission) CanRemoveButton(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("id"), 10, 64)
|
||||
allowed, err := h.service.CanRemoveButton(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "检查失败")
|
||||
return
|
||||
}
|
||||
if !allowed {
|
||||
httpx.Fail(c, "此按钮正在被使用无法删除")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/internal/service/dto"
|
||||
"kra/internal/worker"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Task struct {
|
||||
service *service.TaskService
|
||||
scheduler *worker.TaskScheduler
|
||||
}
|
||||
|
||||
func NewTask(service *service.TaskService, scheduler *worker.TaskScheduler) *Task {
|
||||
return &Task{service: service, scheduler: scheduler}
|
||||
}
|
||||
|
||||
func (h *Task) Create(c *gin.Context) {
|
||||
var req dto.TaskRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
id, err := h.service.CreateRequest(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "创建失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
if err = h.scheduler.ScheduleID(c.Request.Context(), id); err != nil {
|
||||
httpx.Fail(c, "调度失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Task) Update(c *gin.Context) {
|
||||
var req dto.TaskRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.UpdateRequest(c.Request.Context(), &req); err != nil {
|
||||
httpx.Fail(c, "更新失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
if err := h.scheduler.ScheduleID(c.Request.Context(), req.ID); err != nil {
|
||||
httpx.Fail(c, "调度失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Task) Delete(c *gin.Context) {
|
||||
var req dto.DeleteTaskRequest
|
||||
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
h.scheduler.Remove(req.ID)
|
||||
if err := h.service.Delete(c.Request.Context(), req.ID); err != nil {
|
||||
httpx.Fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Task) Toggle(c *gin.Context) {
|
||||
var req dto.ToggleTaskRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.service.Toggle(c.Request.Context(), req.ID, req.Enabled); err != nil {
|
||||
httpx.Fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
if err := h.scheduler.ScheduleID(c.Request.Context(), req.ID); err != nil {
|
||||
httpx.Fail(c, "调度失败")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Task) Trigger(c *gin.Context) {
|
||||
var req dto.DeleteTaskRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.scheduler.TriggerID(c.Request.Context(), req.ID); err != nil {
|
||||
httpx.Fail(c, "任务不存在")
|
||||
return
|
||||
}
|
||||
httpx.OK(c)
|
||||
}
|
||||
|
||||
func (h *Task) List(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
var enabled *bool
|
||||
if raw := c.Query("enabled"); raw != "" {
|
||||
value, _ := strconv.ParseBool(raw)
|
||||
enabled = &value
|
||||
}
|
||||
items, total, err := h.service.ListRequest(c.Request.Context(), page, size, c.Query("name"), c.Query("executorType"), enabled, h.scheduler.NextRuns())
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: page, PageSize: size}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Task) Logs(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
taskID, _ := strconv.ParseUint(c.Query("taskId"), 10, 64)
|
||||
items, total, err := h.service.Logs(c.Request.Context(), page, size, uint(taskID), c.Query("status"))
|
||||
if err != nil {
|
||||
httpx.Fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: page, PageSize: size}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Task) Methods(c *gin.Context) {
|
||||
httpx.Write(c, httpx.CodeSuccess, gin.H{"methods": h.service.RegisteredMethods()}, "获取成功")
|
||||
}
|
||||
|
||||
func (h *Task) AlertStream(c *gin.Context) {
|
||||
c.Header("Content-Type", "text/event-stream")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Header("Connection", "keep-alive")
|
||||
c.Header("X-Accel-Buffering", "no")
|
||||
flusher, ok := c.Writer.(http.Flusher)
|
||||
if !ok {
|
||||
httpx.Fail(c, "SSE 不受支持")
|
||||
return
|
||||
}
|
||||
events := h.scheduler.Subscribe()
|
||||
defer h.scheduler.Unsubscribe(events)
|
||||
ticker := time.NewTicker(20 * time.Second)
|
||||
defer ticker.Stop()
|
||||
_, _ = fmt.Fprint(c.Writer, "event: connected\ndata: {}\n\n")
|
||||
flusher.Flush()
|
||||
for {
|
||||
select {
|
||||
case event, open := <-events:
|
||||
if !open {
|
||||
return
|
||||
}
|
||||
_, _ = fmt.Fprintf(c.Writer, "event: alert\ndata: %s\n\n", event)
|
||||
flusher.Flush()
|
||||
case <-ticker.C:
|
||||
_, _ = fmt.Fprint(c.Writer, ": keepalive\n\n")
|
||||
flusher.Flush()
|
||||
case <-c.Request.Context().Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package httpx
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
CodeSuccess = 0
|
||||
CodeError = 7
|
||||
CodePasswordChangeRequired = 10001
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Data any `json:"data"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
type PageResult struct {
|
||||
List any `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
}
|
||||
|
||||
func Write(c *gin.Context, code int, data any, message string) {
|
||||
c.JSON(http.StatusOK, Response{Code: code, Data: data, Msg: message})
|
||||
}
|
||||
|
||||
func OK(c *gin.Context) { Write(c, CodeSuccess, gin.H{}, "操作成功") }
|
||||
|
||||
func OKWithData(c *gin.Context, data any) { Write(c, CodeSuccess, data, "成功") }
|
||||
|
||||
func Fail(c *gin.Context, message string) { Write(c, CodeError, gin.H{}, message) }
|
||||
|
||||
func NoAuth(c *gin.Context, message string) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, Response{Code: CodeError, Data: nil, Msg: message})
|
||||
}
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type menuRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
ParentID uint `json:"parentId"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Component string `json:"component"`
|
||||
Sort int `json:"sort"`
|
||||
Meta struct {
|
||||
ActiveName string `json:"activeName"`
|
||||
KeepAlive bool `json:"keepAlive"`
|
||||
DefaultMenu bool `json:"defaultMenu"`
|
||||
Title string `json:"title"`
|
||||
Icon string `json:"icon"`
|
||||
CloseTab bool `json:"closeTab"`
|
||||
TransitionType string `json:"transitionType"`
|
||||
} `json:"meta"`
|
||||
MenuButtons []struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"desc"`
|
||||
} `json:"menuBtn"`
|
||||
Parameters []struct {
|
||||
ID uint `json:"ID"`
|
||||
Type string `json:"type"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
} `json:"parameters"`
|
||||
}
|
||||
|
||||
func menuDomain(v menuRequest) *biz.Menu {
|
||||
menu := &biz.Menu{ID: v.ID, ParentID: v.ParentID, Path: v.Path, Name: v.Name, Hidden: v.Hidden, Component: v.Component, Sort: v.Sort, ActiveName: v.Meta.ActiveName, KeepAlive: v.Meta.KeepAlive, DefaultMenu: v.Meta.DefaultMenu, Title: v.Meta.Title, Icon: v.Meta.Icon, CloseTab: v.Meta.CloseTab, TransitionType: v.Meta.TransitionType}
|
||||
menu.Buttons = menuButtons(v, v.ID)
|
||||
menu.Parameters = make([]*biz.MenuParameter, 0, len(v.Parameters))
|
||||
for _, parameter := range v.Parameters {
|
||||
menu.Parameters = append(menu.Parameters, &biz.MenuParameter{ID: parameter.ID, MenuID: v.ID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
|
||||
}
|
||||
return menu
|
||||
}
|
||||
|
||||
func menuButtons(v menuRequest, menuID uint) []*biz.MenuButton {
|
||||
buttons := make([]*biz.MenuButton, 0, len(v.MenuButtons))
|
||||
for _, button := range v.MenuButtons {
|
||||
buttons = append(buttons, &biz.MenuButton{ID: button.ID, Name: button.Name, Description: button.Description, MenuID: menuID})
|
||||
}
|
||||
return buttons
|
||||
}
|
||||
|
||||
func registerMenuRoutes(group *gin.RouterGroup, svc *service.AccessService) {
|
||||
router := group.Group("/menu")
|
||||
router.POST("/getMenuList", func(c *gin.Context) {
|
||||
items, err := svc.Menus(c.Request.Context())
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, pageResult{List: items, Total: int64(len(items)), Page: 1, PageSize: 999}, "获取成功")
|
||||
})
|
||||
router.POST("/getBaseMenuTree", func(c *gin.Context) {
|
||||
items, err := svc.MenuTree(c.Request.Context())
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"menus": items}, "获取成功")
|
||||
})
|
||||
router.POST("/addBaseMenu", func(c *gin.Context) {
|
||||
var req menuRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
menu := menuDomain(req)
|
||||
if err := svc.CreateMenu(c.Request.Context(), menu); err != nil {
|
||||
fail(c, "新增失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/updateBaseMenu", func(c *gin.Context) {
|
||||
var req menuRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.UpdateMenu(c.Request.Context(), menuDomain(req)); err != nil {
|
||||
fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/deleteBaseMenu", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.DeleteMenu(c.Request.Context(), req.ID); err != nil {
|
||||
fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/getBaseMenuById", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
item, err := svc.Menu(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"menu": item}, "获取成功")
|
||||
})
|
||||
router.POST("/addMenuAuthority", func(c *gin.Context) {
|
||||
var req struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
Menus []struct {
|
||||
ID uint `json:"ID"`
|
||||
} `json:"menus"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
ids := make([]uint, 0, len(req.Menus))
|
||||
for _, m := range req.Menus {
|
||||
ids = append(ids, m.ID)
|
||||
}
|
||||
if err := svc.SetAuthorityMenus(c.Request.Context(), req.AuthorityID, ids); err != nil {
|
||||
fail(c, "添加失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/getMenuAuthority", func(c *gin.Context) {
|
||||
var req struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
menus, err := svc.AuthorityMenus(c.Request.Context(), req.AuthorityID)
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"menus": menus}, "获取成功")
|
||||
})
|
||||
router.GET("/getMenuRoles", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("menuId"), 10, 64)
|
||||
ids, err := svc.MenuRoleIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, ids, "获取成功")
|
||||
})
|
||||
router.POST("/setMenuRoles", func(c *gin.Context) {
|
||||
var req struct {
|
||||
MenuID uint `json:"menuId"`
|
||||
AuthorityIDs []uint `json:"authorityIds"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetMenuRoles(c.Request.Context(), req.MenuID, req.AuthorityIDs); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func AccessControl(access *service.AccessService, audit *service.AuditService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
claims := Claims(c)
|
||||
if claims == nil {
|
||||
httpx.NoAuth(c, "未登录或非法访问")
|
||||
return
|
||||
}
|
||||
path := c.Request.URL.Path
|
||||
allowed, err := access.Authorize(c.Request.Context(), claims.AuthorityID, path, c.Request.Method)
|
||||
if err != nil || !allowed {
|
||||
requestID, _ := c.Get("request_id")
|
||||
requestIDText, _ := requestID.(string)
|
||||
_ = audit.RecordDataAccess(c.Request.Context(), &biz.DataAccessLog{EventType: "blocked_access", Operation: c.Request.Method, UserID: claims.ID, AuthorityID: claims.AuthorityID, RequestID: requestIDText, Method: c.Request.Method, Path: path, Detail: "Casbin policy denied the request"})
|
||||
c.AbortWithStatusJSON(http.StatusForbidden, httpx.Response{Code: httpx.CodeError, Data: nil, Msg: "权限不足"})
|
||||
return
|
||||
}
|
||||
scope, err := access.ResolveDataScope(c.Request.Context(), claims.AuthorityID, claims.ID)
|
||||
if err != nil {
|
||||
httpx.Fail(c, "数据权限加载失败")
|
||||
return
|
||||
}
|
||||
c.Request = c.Request.WithContext(biz.NewDataScopeContext(c.Request.Context(), scope))
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kra/internal/conf"
|
||||
"kra/internal/server/httpx"
|
||||
"kra/internal/service"
|
||||
"kra/pkg/adminauth"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const claimsKey = "admin_claims"
|
||||
|
||||
func Auth(config *conf.AdminBackend, settings *service.SettingsService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
token := c.GetHeader("x-token")
|
||||
if token == "" {
|
||||
token, _ = c.Cookie("x-token")
|
||||
}
|
||||
secret := ""
|
||||
if config != nil && config.Jwt != nil {
|
||||
secret = config.Jwt.SigningKey
|
||||
}
|
||||
claims, err := adminauth.Parse(token, secret)
|
||||
if err != nil {
|
||||
httpx.NoAuth(c, "未登录或非法访问")
|
||||
return
|
||||
}
|
||||
if disabled, checkErr := settings.IsTokenDisabled(c.Request.Context(), token); checkErr != nil || disabled {
|
||||
httpx.NoAuth(c, "登录状态已失效")
|
||||
return
|
||||
}
|
||||
if claims.ExpiresAt != nil && claims.BufferTime > 0 && time.Until(claims.ExpiresAt.Time) < time.Duration(claims.BufferTime)*time.Second {
|
||||
expires, buffer := 7*24*time.Hour, time.Duration(claims.BufferTime)*time.Second
|
||||
issuer := claims.Issuer
|
||||
if config != nil && config.Jwt != nil {
|
||||
if config.Jwt.ExpiresTime != nil {
|
||||
expires = config.Jwt.ExpiresTime.AsDuration()
|
||||
}
|
||||
if config.Jwt.BufferTime != nil {
|
||||
buffer = config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
if config.Jwt.Issuer != "" {
|
||||
issuer = config.Jwt.Issuer
|
||||
}
|
||||
}
|
||||
newToken, newClaims, refreshErr := adminauth.Generate(secret, issuer, expires, buffer, claims.ID, claims.AuthorityID, claims.UUID, claims.Username, claims.NickName, claims.MustChangePwd)
|
||||
if refreshErr == nil {
|
||||
c.Header("new-token", newToken)
|
||||
c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt.Unix(), 10))
|
||||
http.SetCookie(c.Writer, &http.Cookie{Name: "x-token", Value: newToken, Path: "/", MaxAge: int(expires.Seconds()), HttpOnly: true, SameSite: http.SameSiteStrictMode})
|
||||
}
|
||||
}
|
||||
c.Set(claimsKey, claims)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func Claims(c *gin.Context) *adminauth.Claims {
|
||||
value, _ := c.Get(claimsKey)
|
||||
claims, _ := value.(*adminauth.Claims)
|
||||
return claims
|
||||
}
|
||||
|
||||
func MustChangePassword() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
claims := Claims(c)
|
||||
if claims == nil || !claims.MustChangePwd {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
path := strings.TrimSuffix(c.Request.URL.Path, "/")
|
||||
if strings.HasSuffix(path, "/user/changePassword") || strings.HasSuffix(path, "/user/getUserInfo") || strings.HasSuffix(path, "/jwt/jsonInBlacklist") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
c.AbortWithStatusJSON(http.StatusConflict, httpx.Response{Code: httpx.CodePasswordChangeRequired, Data: gin.H{"needChangePassword": true}, Msg: "请先修改初始密码"})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func RequestMeta() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
requestID := c.GetHeader("X-Request-Id")
|
||||
if requestID == "" {
|
||||
requestID = uuid.NewString()
|
||||
}
|
||||
c.Header("X-Request-Id", requestID)
|
||||
c.Set("request_id", requestID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerDepartmentRoutes(group *gin.RouterGroup, svc *service.AccessService) {
|
||||
router := group.Group("/department")
|
||||
router.POST("/getDepartmentList", func(c *gin.Context) {
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
_ = c.ShouldBindJSON(&req)
|
||||
items, err := svc.Departments(c.Request.Context(), req.Name)
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, items, "获取成功")
|
||||
})
|
||||
type departmentRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
ParentID uint `json:"parentId"`
|
||||
Sort int `json:"sort"`
|
||||
LeaderID uint `json:"leaderId"`
|
||||
Status bool `json:"status"`
|
||||
}
|
||||
router.POST("/createDepartment", func(c *gin.Context) {
|
||||
var req departmentRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.CreateDepartment(c.Request.Context(), &biz.Department{Name: req.Name, ParentID: req.ParentID, Sort: req.Sort, LeaderID: req.LeaderID, Status: req.Status}); err != nil {
|
||||
fail(c, "创建失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.PUT("/updateDepartment", func(c *gin.Context) {
|
||||
var req departmentRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.UpdateDepartment(c.Request.Context(), &biz.Department{ID: req.ID, Name: req.Name, ParentID: req.ParentID, Sort: req.Sort, LeaderID: req.LeaderID, Status: req.Status}); err != nil {
|
||||
fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.DELETE("/deleteDepartment", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.DeleteDepartment(c.Request.Context(), req.ID); err != nil {
|
||||
fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.GET("/findDepartment", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("id"), 10, 64)
|
||||
item, err := svc.Department(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, item, "获取成功")
|
||||
})
|
||||
router.GET("/getDepartmentUsers", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("deptId"), 10, 64)
|
||||
ids, err := svc.DepartmentUserIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, ids, "获取成功")
|
||||
})
|
||||
router.POST("/setDepartmentUsers", func(c *gin.Context) {
|
||||
var req struct {
|
||||
DepartmentID uint `json:"deptId"`
|
||||
UserIDs []uint `json:"userIds"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetDepartmentUsers(c.Request.Context(), req.DepartmentID, req.UserIDs); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
group.POST("/user/setUserDepartments", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
DepartmentIDs []uint `json:"deptIds"`
|
||||
Primary uint `json:"primaryDeptId"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetUserDepartments(c.Request.Context(), req.ID, req.DepartmentIDs, req.Primary); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
}
|
||||
|
||||
func registerPositionRoutes(group *gin.RouterGroup, svc *service.AccessService) {
|
||||
router := group.Group("/position")
|
||||
router.POST("/getPositionList", func(c *gin.Context) {
|
||||
var req struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
items, total, err := svc.Positions(c.Request.Context(), req.Page, req.PageSize, &biz.Position{Name: req.Name, Code: req.Code})
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, pageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
|
||||
})
|
||||
type positionRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Sort int `json:"sort"`
|
||||
Status bool `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
router.POST("/createPosition", func(c *gin.Context) {
|
||||
var req positionRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.CreatePosition(c.Request.Context(), &biz.Position{Name: req.Name, Code: req.Code, Sort: req.Sort, Status: req.Status, Remark: req.Remark}); err != nil {
|
||||
fail(c, "创建失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.PUT("/updatePosition", func(c *gin.Context) {
|
||||
var req positionRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.UpdatePosition(c.Request.Context(), &biz.Position{ID: req.ID, Name: req.Name, Code: req.Code, Sort: req.Sort, Status: req.Status, Remark: req.Remark}); err != nil {
|
||||
fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.DELETE("/deletePosition", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.DeletePosition(c.Request.Context(), req.ID); err != nil {
|
||||
fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.GET("/findPosition", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("id"), 10, 64)
|
||||
item, err := svc.Position(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, item, "获取成功")
|
||||
})
|
||||
router.GET("/getPositionUsers", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("positionId"), 10, 64)
|
||||
ids, err := svc.PositionUserIDs(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, ids, "获取成功")
|
||||
})
|
||||
router.POST("/setPositionUsers", func(c *gin.Context) {
|
||||
var req struct {
|
||||
PositionID uint `json:"positionId"`
|
||||
UserIDs []uint `json:"userIds"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetPositionUsers(c.Request.Context(), req.PositionID, req.UserIDs); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
group.POST("/user/setUserPositions", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
PositionIDs []uint `json:"positionIds"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetUserPositions(c.Request.Context(), req.ID, req.PositionIDs); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerPolicyRoutes(group *gin.RouterGroup, svc *service.AccessService) {
|
||||
casbin := group.Group("/casbin")
|
||||
casbin.POST("/updateCasbin", func(c *gin.Context) {
|
||||
var req struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
Infos []struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
} `json:"casbinInfos"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
paths := make([]*biz.API, 0, len(req.Infos))
|
||||
for _, v := range req.Infos {
|
||||
paths = append(paths, &biz.API{Path: v.Path, Method: v.Method})
|
||||
}
|
||||
if err := svc.SetPolicyPaths(c.Request.Context(), req.AuthorityID, paths); err != nil {
|
||||
fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
casbin.POST("/getPolicyPathByAuthorityId", func(c *gin.Context) {
|
||||
var req struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
paths, err := svc.PolicyPaths(c.Request.Context(), req.AuthorityID)
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"paths": paths}, "获取成功")
|
||||
})
|
||||
buttons := group.Group("/authorityBtn")
|
||||
buttons.POST("/getAuthorityBtn", func(c *gin.Context) {
|
||||
var req struct {
|
||||
MenuID uint `json:"menuID"`
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
selected, err := svc.SelectedButtons(c.Request.Context(), req.AuthorityID, req.MenuID)
|
||||
if err != nil {
|
||||
fail(c, "查询失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, gin.H{"selected": selected}, "查询成功")
|
||||
})
|
||||
buttons.POST("/setAuthorityBtn", func(c *gin.Context) {
|
||||
var req struct {
|
||||
MenuID uint `json:"menuID"`
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
Selected []uint `json:"selected"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.SetSelectedButtons(c.Request.Context(), req.AuthorityID, req.MenuID, req.Selected); err != nil {
|
||||
fail(c, "分配失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
buttons.POST("/canRemoveAuthorityBtn", func(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Query("id"), 10, 64)
|
||||
allowed, err := svc.CanRemoveButton(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
fail(c, "检查失败")
|
||||
return
|
||||
}
|
||||
if !allowed {
|
||||
fail(c, "此按钮正在被使用无法删除")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
}
|
||||
|
|
@ -1,50 +1,29 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"kra/internal/server/httpx"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
codeSuccess = 0
|
||||
codeError = 7
|
||||
codePasswordChangeRequired = 10001
|
||||
codeSuccess = httpx.CodeSuccess
|
||||
codeError = httpx.CodeError
|
||||
codePasswordChangeRequired = httpx.CodePasswordChangeRequired
|
||||
)
|
||||
|
||||
type response struct {
|
||||
Code int `json:"code"`
|
||||
Data any `json:"data"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
type response = httpx.Response
|
||||
|
||||
type pageResult struct {
|
||||
List any `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
}
|
||||
type pageResult = httpx.PageResult
|
||||
|
||||
func writeResult(c *gin.Context, code int, data any, message string) {
|
||||
c.JSON(http.StatusOK, response{Code: code, Data: data, Msg: message})
|
||||
httpx.Write(c, code, data, message)
|
||||
}
|
||||
|
||||
func ok(c *gin.Context) {
|
||||
writeResult(c, codeSuccess, gin.H{}, "操作成功")
|
||||
}
|
||||
func ok(c *gin.Context) { httpx.OK(c) }
|
||||
|
||||
func okWithData(c *gin.Context, data any) {
|
||||
writeResult(c, codeSuccess, data, "成功")
|
||||
}
|
||||
func okWithData(c *gin.Context, data any) { httpx.OKWithData(c, data) }
|
||||
|
||||
func fail(c *gin.Context, message string) {
|
||||
writeResult(c, codeError, gin.H{}, message)
|
||||
}
|
||||
func fail(c *gin.Context, message string) { httpx.Fail(c, message) }
|
||||
|
||||
func noAuth(c *gin.Context, message string) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, response{
|
||||
Code: codeError,
|
||||
Data: nil,
|
||||
Msg: message,
|
||||
})
|
||||
}
|
||||
func noAuth(c *gin.Context, message string) { httpx.NoAuth(c, message) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterAnnouncement(private, public *gin.RouterGroup, h *handler.Announcement) {
|
||||
privateInfo := private.Group("/info")
|
||||
privateInfo.POST("/createInfo", h.Create)
|
||||
privateInfo.DELETE("/deleteInfo", h.Delete)
|
||||
privateInfo.DELETE("/deleteInfoByIds", h.DeleteByIDs)
|
||||
privateInfo.PUT("/updateInfo", h.Update)
|
||||
privateInfo.GET("/findInfo", h.Find)
|
||||
privateInfo.GET("/getInfoList", h.List)
|
||||
publicInfo := public.Group("/info")
|
||||
publicInfo.GET("/getInfoDataSource", h.DataSource)
|
||||
publicInfo.GET("/getInfoPublic", h.Public)
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterAPI(group *gin.RouterGroup, engine *gin.Engine, h *handler.API) {
|
||||
api := group.Group("/api")
|
||||
api.POST("/getApiList", h.List)
|
||||
api.POST("/getAllApis", h.All)
|
||||
api.POST("/createApi", h.Create)
|
||||
api.POST("/updateApi", h.Update)
|
||||
api.POST("/deleteApi", h.Delete)
|
||||
api.DELETE("/deleteApisByIds", h.DeleteByIDs)
|
||||
api.POST("/getApiById", h.Find)
|
||||
api.GET("/getApiGroups", h.Groups)
|
||||
api.GET("/getApiRoles", h.Roles)
|
||||
api.POST("/setApiRoles", h.SetRoles)
|
||||
api.GET("/syncApi", h.Sync(engine))
|
||||
api.POST("/ignoreApi", h.Ignore)
|
||||
api.POST("/enterSyncApi", h.ApplySync)
|
||||
api.GET("/freshCasbin", h.FreshCasbin)
|
||||
casbin := group.Group("/casbin")
|
||||
casbin.POST("/updateCasbin", h.SetPolicyPaths)
|
||||
casbin.POST("/getPolicyPathByAuthorityId", h.PolicyPaths)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterAuthority(group *gin.RouterGroup, h *handler.Authority) {
|
||||
router := group.Group("/authority")
|
||||
router.POST("/getAuthorityList", h.List)
|
||||
router.POST("/createAuthority", h.Create)
|
||||
router.POST("/copyAuthority", h.Copy)
|
||||
router.PUT("/updateAuthority", h.Update)
|
||||
router.POST("/deleteAuthority", h.Delete)
|
||||
router.POST("/setRoleUsers", h.SetUsers)
|
||||
router.GET("/getUsersByAuthority", h.Users)
|
||||
router.POST("/setDataScope", h.SetDataScope)
|
||||
router.GET("/getDataScopeDepts", h.DataScopeDepartments)
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterEmail(group *gin.RouterGroup, h *handler.Email) {
|
||||
email := group.Group("/email")
|
||||
email.POST("/emailTest", h.Test)
|
||||
email.POST("/sendEmail", h.Send)
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterMenu(group *gin.RouterGroup, h *handler.Menu) {
|
||||
router := group.Group("/menu")
|
||||
router.POST("/getMenuList", h.List)
|
||||
router.POST("/getBaseMenuTree", h.Tree)
|
||||
router.POST("/addBaseMenu", h.Create)
|
||||
router.POST("/updateBaseMenu", h.Update)
|
||||
router.POST("/deleteBaseMenu", h.Delete)
|
||||
router.POST("/getBaseMenuById", h.Find)
|
||||
router.POST("/addMenuAuthority", h.SetAuthorityMenus)
|
||||
router.POST("/getMenuAuthority", h.AuthorityMenus)
|
||||
router.GET("/getMenuRoles", h.RoleIDs)
|
||||
router.POST("/setMenuRoles", h.SetRoles)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterOrganization(group *gin.RouterGroup, h *handler.Organization) {
|
||||
departments := group.Group("/department")
|
||||
departments.POST("/getDepartmentList", h.ListDepartments)
|
||||
departments.POST("/createDepartment", h.CreateDepartment)
|
||||
departments.PUT("/updateDepartment", h.UpdateDepartment)
|
||||
departments.DELETE("/deleteDepartment", h.DeleteDepartment)
|
||||
departments.GET("/findDepartment", h.FindDepartment)
|
||||
departments.GET("/getDepartmentUsers", h.DepartmentUsers)
|
||||
departments.POST("/setDepartmentUsers", h.SetDepartmentUsers)
|
||||
group.POST("/user/setUserDepartments", h.SetUserDepartments)
|
||||
|
||||
positions := group.Group("/position")
|
||||
positions.POST("/getPositionList", h.ListPositions)
|
||||
positions.POST("/createPosition", h.CreatePosition)
|
||||
positions.PUT("/updatePosition", h.UpdatePosition)
|
||||
positions.DELETE("/deletePosition", h.DeletePosition)
|
||||
positions.GET("/findPosition", h.FindPosition)
|
||||
positions.GET("/getPositionUsers", h.PositionUsers)
|
||||
positions.POST("/setPositionUsers", h.SetPositionUsers)
|
||||
group.POST("/user/setUserPositions", h.SetUserPositions)
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterPermission(group *gin.RouterGroup, h *handler.Permission) {
|
||||
buttons := group.Group("/authorityBtn")
|
||||
buttons.POST("/getAuthorityBtn", h.Buttons)
|
||||
buttons.POST("/setAuthorityBtn", h.SetButtons)
|
||||
buttons.POST("/canRemoveAuthorityBtn", h.CanRemoveButton)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterTask(group *gin.RouterGroup, h *handler.Task) {
|
||||
router := group.Group("/timedTask")
|
||||
router.POST("/createTimedTask", h.Create)
|
||||
router.PUT("/updateTimedTask", h.Update)
|
||||
router.DELETE("/deleteTimedTask", h.Delete)
|
||||
router.POST("/toggleTimedTask", h.Toggle)
|
||||
router.POST("/triggerTimedTask", h.Trigger)
|
||||
router.GET("/getTimedTaskList", h.List)
|
||||
router.GET("/getTimedTaskLogList", h.Logs)
|
||||
router.GET("/getRegisteredMethods", h.Methods)
|
||||
router.GET("/alertStream", h.AlertStream)
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
"kra/internal/worker"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// ProviderSet is server providers.
|
||||
var ProviderSet = wire.NewSet(NewGinServer, NewTaskScheduler)
|
||||
var ProviderSet = wire.NewSet(NewGinServer, handler.NewAuthority, handler.NewMenu, handler.NewAPI, handler.NewPermission, handler.NewOrganization, handler.NewAnnouncement, handler.NewEmail, handler.NewTask, worker.NewTaskScheduler)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"kra/internal/biz"
|
||||
"kra/internal/conf"
|
||||
"kra/internal/service"
|
||||
"kra/internal/worker"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shirou/gopsutil/v4/cpu"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func registerSystemConfigRoutes(group *gin.RouterGroup, config *conf.AdminBackend, systemService *service.SystemService, settings *service.SettingsService, scheduler *TaskScheduler) {
|
||||
func registerSystemConfigRoutes(group *gin.RouterGroup, config *conf.AdminBackend, systemService *service.SystemService, settings *service.SettingsService, scheduler *worker.TaskScheduler) {
|
||||
security := group.Group("/securityConfig")
|
||||
security.GET("/getSecurityConfig", func(c *gin.Context) {
|
||||
value, err := settings.Security(c.Request.Context())
|
||||
|
|
|
|||
|
|
@ -1,187 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
)
|
||||
|
||||
type taskRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Spec string `json:"spec"`
|
||||
WithSeconds bool `json:"withSeconds"`
|
||||
ExecutorType string `json:"executorType"`
|
||||
MethodName string `json:"methodName"`
|
||||
Params json.RawMessage `json:"params"`
|
||||
HTTPURL string `json:"httpUrl"`
|
||||
HTTPMethod string `json:"httpMethod"`
|
||||
HTTPHeader json.RawMessage `json:"httpHeader"`
|
||||
HTTPBody string `json:"httpBody"`
|
||||
HTTPAllowPrivate bool `json:"httpAllowPrivate"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func taskDomain(v taskRequest) *biz.TimedTask {
|
||||
return &biz.TimedTask{ID: v.ID, Name: v.Name, Description: v.Description, Spec: v.Spec, WithSeconds: v.WithSeconds, ExecutorType: v.ExecutorType, MethodName: v.MethodName, Params: v.Params, HTTPURL: v.HTTPURL, HTTPMethod: v.HTTPMethod, HTTPHeader: v.HTTPHeader, HTTPBody: v.HTTPBody, HTTPAllowPrivate: v.HTTPAllowPrivate, Enabled: v.Enabled}
|
||||
}
|
||||
func registerTaskRoutes(group *gin.RouterGroup, svc *service.TaskService, scheduler *TaskScheduler) {
|
||||
router := group.Group("/timedTask")
|
||||
router.POST("/createTimedTask", func(c *gin.Context) {
|
||||
var req taskRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
task := taskDomain(req)
|
||||
if err := svc.Create(c.Request.Context(), task); err != nil {
|
||||
fail(c, "创建失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
if err := scheduler.Schedule(task); err != nil {
|
||||
fail(c, "调度失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.PUT("/updateTimedTask", func(c *gin.Context) {
|
||||
var req taskRequest
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
task := taskDomain(req)
|
||||
if err := svc.Update(c.Request.Context(), task); err != nil {
|
||||
fail(c, "更新失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
if err := scheduler.Schedule(task); err != nil {
|
||||
fail(c, "调度失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.DELETE("/deleteTimedTask", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
scheduler.Remove(req.ID)
|
||||
if err := svc.Delete(c.Request.Context(), req.ID); err != nil {
|
||||
fail(c, "删除失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/toggleTimedTask", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
if err := svc.Toggle(c.Request.Context(), req.ID, req.Enabled); err != nil {
|
||||
fail(c, "设置失败")
|
||||
return
|
||||
}
|
||||
task, err := svc.Task(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
fail(c, "任务不存在")
|
||||
return
|
||||
}
|
||||
if err = scheduler.Schedule(task); err != nil {
|
||||
fail(c, "调度失败")
|
||||
return
|
||||
}
|
||||
ok(c)
|
||||
})
|
||||
router.POST("/triggerTimedTask", func(c *gin.Context) {
|
||||
var req struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
if c.ShouldBindJSON(&req) != nil {
|
||||
fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
task, err := svc.Task(c.Request.Context(), req.ID)
|
||||
if err != nil {
|
||||
fail(c, "任务不存在")
|
||||
return
|
||||
}
|
||||
scheduler.Trigger(task)
|
||||
ok(c)
|
||||
})
|
||||
router.GET("/getTimedTaskList", func(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
var enabled *bool
|
||||
if raw := c.Query("enabled"); raw != "" {
|
||||
value, _ := strconv.ParseBool(raw)
|
||||
enabled = &value
|
||||
}
|
||||
items, total, err := svc.Tasks(c.Request.Context(), page, size, &biz.TimedTask{Name: c.Query("name"), ExecutorType: c.Query("executorType"), EnabledFilter: enabled}, scheduler.NextRuns())
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, pageResult{List: items, Total: total, Page: page, PageSize: size}, "获取成功")
|
||||
})
|
||||
router.GET("/getTimedTaskLogList", func(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
taskID, _ := strconv.ParseUint(c.Query("taskId"), 10, 64)
|
||||
items, total, err := svc.Logs(c.Request.Context(), page, size, uint(taskID), c.Query("status"))
|
||||
if err != nil {
|
||||
fail(c, "获取失败")
|
||||
return
|
||||
}
|
||||
writeResult(c, codeSuccess, pageResult{List: items, Total: total, Page: page, PageSize: size}, "获取成功")
|
||||
})
|
||||
router.GET("/getRegisteredMethods", func(c *gin.Context) {
|
||||
writeResult(c, codeSuccess, gin.H{"methods": svc.RegisteredMethods()}, "获取成功")
|
||||
})
|
||||
router.GET("/alertStream", func(c *gin.Context) {
|
||||
c.Header("Content-Type", "text/event-stream")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Header("Connection", "keep-alive")
|
||||
c.Header("X-Accel-Buffering", "no")
|
||||
flusher, okFlush := c.Writer.(http.Flusher)
|
||||
if !okFlush {
|
||||
fail(c, "SSE 不受支持")
|
||||
return
|
||||
}
|
||||
events := scheduler.Subscribe()
|
||||
defer scheduler.Unsubscribe(events)
|
||||
ticker := time.NewTicker(20 * time.Second)
|
||||
defer ticker.Stop()
|
||||
_, _ = fmt.Fprint(c.Writer, "event: connected\ndata: {}\n\n")
|
||||
flusher.Flush()
|
||||
for {
|
||||
select {
|
||||
case event, open := <-events:
|
||||
if !open {
|
||||
return
|
||||
}
|
||||
_, _ = fmt.Fprintf(c.Writer, "event: alert\ndata: %s\n\n", event)
|
||||
flusher.Flush()
|
||||
case <-ticker.C:
|
||||
_, _ = fmt.Fprint(c.Writer, ": keepalive\n\n")
|
||||
flusher.Flush()
|
||||
case <-c.Request.Context().Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type AccessService struct{ uc *biz.AccessUsecase }
|
||||
|
|
@ -63,32 +64,32 @@ func (s *AccessService) UpdateAuthority(ctx context.Context, v *biz.Authority) e
|
|||
func (s *AccessService) DeleteAuthority(ctx context.Context, id uint) error {
|
||||
return s.uc.Repo().DeleteAuthority(ctx, id)
|
||||
}
|
||||
func (s *AccessService) SetAuthorityMenus(ctx context.Context, id uint, ids []uint) error {
|
||||
return s.uc.Repo().SetAuthorityMenus(ctx, id, ids)
|
||||
func authorityDomain(req *dto.AuthorityRequest) *biz.Authority {
|
||||
return &biz.Authority{AuthorityID: req.AuthorityID, AuthorityName: req.AuthorityName, ParentID: req.ParentID, DataScope: req.DataScope, DefaultRouter: req.DefaultRouter}
|
||||
}
|
||||
func (s *AccessService) AuthorityMenuIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return s.uc.Repo().AuthorityMenuIDs(ctx, id)
|
||||
func authorityResponse(value *biz.Authority) *dto.AuthorityResponse {
|
||||
return &dto.AuthorityResponse{AuthorityID: value.AuthorityID, AuthorityName: value.AuthorityName, ParentID: value.ParentID, DataScope: value.DataScope, DefaultRouter: value.DefaultRouter}
|
||||
}
|
||||
func (s *AccessService) AuthorityMenus(ctx context.Context, id uint) ([]map[string]any, error) {
|
||||
ids, err := s.uc.Repo().AuthorityMenuIDs(ctx, id)
|
||||
if err != nil {
|
||||
func (s *AccessService) CreateAuthorityRequest(ctx context.Context, req *dto.AuthorityRequest) (*dto.AuthorityResponse, error) {
|
||||
value := authorityDomain(req)
|
||||
if err := s.CreateAuthority(ctx, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selected := make(map[uint]bool, len(ids))
|
||||
for _, value := range ids {
|
||||
selected[value] = true
|
||||
}
|
||||
menus, err := s.uc.Repo().ListMenus(ctx)
|
||||
if err != nil {
|
||||
return authorityResponse(value), nil
|
||||
}
|
||||
func (s *AccessService) CopyAuthorityRequest(ctx context.Context, req *dto.CopyAuthorityRequest) (*dto.AuthorityResponse, error) {
|
||||
value := authorityDomain(&req.Authority)
|
||||
if err := s.CopyAuthority(ctx, req.OldAuthorityID, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(ids))
|
||||
for _, menu := range menus {
|
||||
if selected[menu.ID] {
|
||||
out = append(out, map[string]any{"menuId": menu.ID, "authorityId": id, "sysBaseMenu": convertMenu(menu), "parentId": menu.ParentID})
|
||||
}
|
||||
return authorityResponse(value), nil
|
||||
}
|
||||
func (s *AccessService) UpdateAuthorityRequest(ctx context.Context, req *dto.AuthorityRequest) (*dto.AuthorityResponse, error) {
|
||||
value := authorityDomain(req)
|
||||
if err := s.UpdateAuthority(ctx, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
return authorityResponse(value), nil
|
||||
}
|
||||
func (s *AccessService) SetAuthorityUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return s.uc.Repo().SetAuthorityUsers(ctx, id, ids)
|
||||
|
|
@ -106,127 +107,16 @@ func (s *AccessService) ResolveDataScope(ctx context.Context, authorityID, userI
|
|||
return s.uc.Repo().ResolveDataScope(ctx, authorityID, userID)
|
||||
}
|
||||
|
||||
func (s *AccessService) Menus(ctx context.Context) ([]map[string]any, error) {
|
||||
items, err := s.uc.Repo().ListMenus(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
v.Buttons, err = s.uc.Repo().Buttons(ctx, v.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, convertMenu(v))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *AccessService) MenuTree(ctx context.Context) ([]map[string]any, error) {
|
||||
items, err := s.uc.Repo().ListMenus(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byID := make(map[uint]*biz.Menu, len(items))
|
||||
for _, item := range items {
|
||||
item.Buttons, err = s.uc.Repo().Buttons(ctx, item.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item.Children = []*biz.Menu{}
|
||||
byID[item.ID] = item
|
||||
}
|
||||
roots := make([]*biz.Menu, 0)
|
||||
for _, item := range items {
|
||||
if parent := byID[item.ParentID]; parent != nil {
|
||||
parent.Children = append(parent.Children, item)
|
||||
} else {
|
||||
roots = append(roots, item)
|
||||
}
|
||||
}
|
||||
out := make([]map[string]any, 0, len(roots))
|
||||
for _, item := range roots {
|
||||
out = append(out, convertMenu(item))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *AccessService) CreateMenu(ctx context.Context, v *biz.Menu) error {
|
||||
return s.uc.Repo().CreateMenu(ctx, v)
|
||||
}
|
||||
func (s *AccessService) UpdateMenu(ctx context.Context, v *biz.Menu) error {
|
||||
return s.uc.Repo().UpdateMenu(ctx, v)
|
||||
}
|
||||
func (s *AccessService) DeleteMenu(ctx context.Context, id uint) error {
|
||||
return s.uc.Repo().DeleteMenu(ctx, id)
|
||||
}
|
||||
func (s *AccessService) Menu(ctx context.Context, id uint) (map[string]any, error) {
|
||||
v, err := s.uc.Repo().FindMenu(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v.Buttons, err = s.uc.Repo().Buttons(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertMenu(v), nil
|
||||
}
|
||||
func (s *AccessService) MenuRoleIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return s.uc.Repo().MenuRoleIDs(ctx, id)
|
||||
}
|
||||
func (s *AccessService) SetMenuRoles(ctx context.Context, id uint, ids []uint) error {
|
||||
return s.uc.Repo().SetMenuRoles(ctx, id, ids)
|
||||
}
|
||||
func (s *AccessService) ReplaceMenuButtons(ctx context.Context, menuID uint, buttons []*biz.MenuButton) error {
|
||||
return s.uc.Repo().ReplaceMenuButtons(ctx, menuID, buttons)
|
||||
}
|
||||
|
||||
func (s *AccessService) APIs(ctx context.Context, page, size int, q *biz.API) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.uc.Repo().ListAPIs(ctx, page, size, q)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, apiDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *AccessService) CreateAPI(ctx context.Context, v *biz.API) error {
|
||||
return s.uc.Repo().CreateAPI(ctx, v)
|
||||
}
|
||||
func (s *AccessService) UpdateAPI(ctx context.Context, v *biz.API) error {
|
||||
return s.uc.Repo().UpdateAPI(ctx, v)
|
||||
}
|
||||
func (s *AccessService) DeleteAPIs(ctx context.Context, ids []uint) error {
|
||||
return s.uc.Repo().DeleteAPIs(ctx, ids)
|
||||
}
|
||||
func (s *AccessService) API(ctx context.Context, id uint) (map[string]any, error) {
|
||||
v, err := s.uc.Repo().FindAPI(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apiDTO(v), nil
|
||||
}
|
||||
func (s *AccessService) APIRoleIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return s.uc.Repo().APIRoleIDs(ctx, id)
|
||||
}
|
||||
func (s *AccessService) SetAPIRoles(ctx context.Context, id uint, ids []uint) error {
|
||||
return s.uc.Repo().SetAPIRoles(ctx, id, ids)
|
||||
}
|
||||
func (s *AccessService) PolicyPaths(ctx context.Context, id uint) ([]map[string]any, error) {
|
||||
items, err := s.uc.Repo().PolicyPaths(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, map[string]any{"path": v.Path, "method": v.Method})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *AccessService) SetPolicyPaths(ctx context.Context, id uint, paths []*biz.API) error {
|
||||
return s.uc.Repo().SetPolicyPaths(ctx, id, paths)
|
||||
}
|
||||
func (s *AccessService) SyncAPIs(ctx context.Context, routes []*biz.API) (map[string]any, error) {
|
||||
func (s *AccessService) SyncAPIs(ctx context.Context, routes []*biz.API) (*dto.APISyncResponse, error) {
|
||||
stored, _, err := s.uc.Repo().ListAPIs(ctx, 1, 100000, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -250,31 +140,27 @@ func (s *AccessService) SyncAPIs(ctx context.Context, routes []*biz.API) (map[st
|
|||
for _, item := range stored {
|
||||
storedSet[key(item)] = item
|
||||
}
|
||||
added := make([]map[string]any, 0)
|
||||
deleted := make([]map[string]any, 0)
|
||||
ignoredDTO := make([]map[string]any, 0, len(ignored))
|
||||
added := make([]*dto.APIResponse, 0)
|
||||
deleted := make([]*dto.APIResponse, 0)
|
||||
ignoredDTO := make([]*dto.APIResponse, 0, len(ignored))
|
||||
for k, item := range routeSet {
|
||||
if storedSet[k] == nil {
|
||||
added = append(added, apiDTO(item))
|
||||
added = append(added, apiResponse(item))
|
||||
}
|
||||
}
|
||||
for k, item := range storedSet {
|
||||
if routeSet[k] == nil && !ignoreSet[k] {
|
||||
deleted = append(deleted, apiDTO(item))
|
||||
deleted = append(deleted, apiResponse(item))
|
||||
}
|
||||
}
|
||||
for _, item := range ignored {
|
||||
ignoredDTO = append(ignoredDTO, apiDTO(item))
|
||||
ignoredDTO = append(ignoredDTO, apiResponse(item))
|
||||
}
|
||||
return map[string]any{"newApis": added, "deleteApis": deleted, "ignoreApis": ignoredDTO}, nil
|
||||
return &dto.APISyncResponse{NewAPIs: added, DeleteAPIs: deleted, IgnoreAPIs: ignoredDTO}, nil
|
||||
}
|
||||
func (s *AccessService) SetAPIIgnored(ctx context.Context, path, method string, ignored bool) error {
|
||||
return s.uc.Repo().SetAPIIgnored(ctx, path, method, ignored)
|
||||
}
|
||||
func (s *AccessService) ApplyAPISync(ctx context.Context, added, deleted []*biz.API) error {
|
||||
return s.uc.Repo().ApplyAPISync(ctx, added, deleted)
|
||||
}
|
||||
|
||||
func (s *AccessService) Buttons(ctx context.Context, id uint) ([]map[string]any, error) {
|
||||
items, err := s.uc.Repo().Buttons(ctx, id)
|
||||
if err != nil {
|
||||
|
|
@ -301,77 +187,3 @@ func (s *AccessService) SetSelectedButtons(ctx context.Context, aid, menuID uint
|
|||
func (s *AccessService) CanRemoveButton(ctx context.Context, id uint) (bool, error) {
|
||||
return s.uc.Repo().CanRemoveButton(ctx, id)
|
||||
}
|
||||
|
||||
func (s *AccessService) Departments(ctx context.Context, name string) ([]map[string]any, error) {
|
||||
items, err := s.uc.Repo().ListDepartments(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, departmentDTO(v))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *AccessService) CreateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
return s.uc.Repo().CreateDepartment(ctx, v)
|
||||
}
|
||||
func (s *AccessService) UpdateDepartment(ctx context.Context, v *biz.Department) error {
|
||||
return s.uc.Repo().UpdateDepartment(ctx, v)
|
||||
}
|
||||
func (s *AccessService) DeleteDepartment(ctx context.Context, id uint) error {
|
||||
return s.uc.Repo().DeleteDepartment(ctx, id)
|
||||
}
|
||||
func (s *AccessService) Department(ctx context.Context, id uint) (map[string]any, error) {
|
||||
v, err := s.uc.Repo().FindDepartment(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return departmentDTO(v), nil
|
||||
}
|
||||
func (s *AccessService) DepartmentUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return s.uc.Repo().DepartmentUserIDs(ctx, id)
|
||||
}
|
||||
func (s *AccessService) SetDepartmentUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return s.uc.Repo().SetDepartmentUsers(ctx, id, ids)
|
||||
}
|
||||
func (s *AccessService) SetUserDepartments(ctx context.Context, id uint, ids []uint, primary uint) error {
|
||||
return s.uc.Repo().SetUserDepartments(ctx, id, ids, primary)
|
||||
}
|
||||
|
||||
func (s *AccessService) Positions(ctx context.Context, page, size int, q *biz.Position) ([]map[string]any, int64, error) {
|
||||
items, total, err := s.uc.Repo().ListPositions(ctx, page, size, q)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(items))
|
||||
for _, v := range items {
|
||||
out = append(out, positionDTO(v))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *AccessService) CreatePosition(ctx context.Context, v *biz.Position) error {
|
||||
return s.uc.Repo().CreatePosition(ctx, v)
|
||||
}
|
||||
func (s *AccessService) UpdatePosition(ctx context.Context, v *biz.Position) error {
|
||||
return s.uc.Repo().UpdatePosition(ctx, v)
|
||||
}
|
||||
func (s *AccessService) DeletePosition(ctx context.Context, id uint) error {
|
||||
return s.uc.Repo().DeletePosition(ctx, id)
|
||||
}
|
||||
func (s *AccessService) Position(ctx context.Context, id uint) (map[string]any, error) {
|
||||
v, err := s.uc.Repo().FindPosition(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return positionDTO(v), nil
|
||||
}
|
||||
func (s *AccessService) PositionUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return s.uc.Repo().PositionUserIDs(ctx, id)
|
||||
}
|
||||
func (s *AccessService) SetPositionUsers(ctx context.Context, id uint, ids []uint) error {
|
||||
return s.uc.Repo().SetPositionUsers(ctx, id, ids)
|
||||
}
|
||||
func (s *AccessService) SetUserPositions(ctx context.Context, id uint, ids []uint) error {
|
||||
return s.uc.Repo().SetUserPositions(ctx, id, ids)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
func apiDomain(value *dto.APIRequest) *biz.API {
|
||||
return &biz.API{ID: value.ID, Path: value.Path, Description: value.Description, APIGroup: value.APIGroup, Method: value.Method}
|
||||
}
|
||||
|
||||
func apiResponse(value *biz.API) *dto.APIResponse {
|
||||
return &dto.APIResponse{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: nil, Path: value.Path, Description: value.Description, APIGroup: value.APIGroup, Method: value.Method}
|
||||
}
|
||||
|
||||
func apiResponses(items []*biz.API) []*dto.APIResponse {
|
||||
out := make([]*dto.APIResponse, 0, len(items))
|
||||
for _, item := range items {
|
||||
out = append(out, apiResponse(item))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *AccessService) ListAPI(ctx context.Context, req *dto.APIListRequest) ([]*dto.APIResponse, int64, error) {
|
||||
items, total, err := s.uc.Repo().ListAPIs(ctx, req.Page, req.PageSize, &biz.API{Path: req.Path, Description: req.Description, APIGroup: req.APIGroup, Method: req.Method})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return apiResponses(items), total, nil
|
||||
}
|
||||
|
||||
func (s *AccessService) AllAPI(ctx context.Context) ([]*dto.APIResponse, error) {
|
||||
items, _, err := s.uc.Repo().ListAPIs(ctx, 1, 10000, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apiResponses(items), nil
|
||||
}
|
||||
|
||||
func (s *AccessService) CreateAPIRequest(ctx context.Context, req *dto.APIRequest) error {
|
||||
return s.uc.Repo().CreateAPI(ctx, apiDomain(req))
|
||||
}
|
||||
func (s *AccessService) UpdateAPIRequest(ctx context.Context, req *dto.APIRequest) error {
|
||||
return s.uc.Repo().UpdateAPI(ctx, apiDomain(req))
|
||||
}
|
||||
func (s *AccessService) FindAPIResponse(ctx context.Context, id uint) (*dto.APIResponse, error) {
|
||||
value, err := s.uc.Repo().FindAPI(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apiResponse(value), nil
|
||||
}
|
||||
func (s *AccessService) ApplyAPISyncRequest(ctx context.Context, req *dto.ApplyAPISyncRequest) error {
|
||||
added := make([]*biz.API, 0, len(req.NewAPIs))
|
||||
deleted := make([]*biz.API, 0, len(req.DeleteAPIs))
|
||||
for i := range req.NewAPIs {
|
||||
added = append(added, apiDomain(&req.NewAPIs[i]))
|
||||
}
|
||||
for i := range req.DeleteAPIs {
|
||||
deleted = append(deleted, apiDomain(&req.DeleteAPIs[i]))
|
||||
}
|
||||
return s.uc.Repo().ApplyAPISync(ctx, added, deleted)
|
||||
}
|
||||
func (s *AccessService) SetPolicyPathsRequest(ctx context.Context, req *dto.SetPolicyPathsRequest) error {
|
||||
paths := make([]*biz.API, 0, len(req.Infos))
|
||||
for _, value := range req.Infos {
|
||||
paths = append(paths, &biz.API{Path: value.Path, Method: value.Method})
|
||||
}
|
||||
return s.uc.Repo().SetPolicyPaths(ctx, req.AuthorityID, paths)
|
||||
}
|
||||
func (s *AccessService) PolicyPathResponses(ctx context.Context, authorityID uint) ([]dto.PolicyPathRequest, error) {
|
||||
items, err := s.uc.Repo().PolicyPaths(ctx, authorityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]dto.PolicyPathRequest, 0, len(items))
|
||||
for _, item := range items {
|
||||
out = append(out, dto.PolicyPathRequest{Path: item.Path, Method: item.Method})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *AccessService) SyncAPIResponses(ctx context.Context, routes []dto.APIRequest) (*dto.APISyncResponse, error) {
|
||||
items := make([]*biz.API, 0, len(routes))
|
||||
for i := range routes {
|
||||
items = append(items, apiDomain(&routes[i]))
|
||||
}
|
||||
return s.SyncAPIs(ctx, items)
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package dto
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type AnnouncementRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
UserID *uint `json:"userID"`
|
||||
Attachments json.RawMessage `json:"attachments"`
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package dto
|
||||
|
||||
import "time"
|
||||
|
||||
type APIRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
APIGroup string `json:"apiGroup"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
||||
type APIListRequest struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
APIGroup string `json:"apiGroup"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
||||
type APIResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
CreatedAt time.Time `json:"CreatedAt"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt"`
|
||||
DeletedAt any `json:"DeletedAt"`
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
APIGroup string `json:"apiGroup"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
||||
type DeleteAPIRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
type DeleteAPIsRequest struct {
|
||||
IDs []uint `json:"ids"`
|
||||
}
|
||||
type GetAPIRequest struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
type SetAPIRolesRequest struct {
|
||||
APIID uint `json:"apiId"`
|
||||
AuthorityIDs []uint `json:"authorityIds"`
|
||||
}
|
||||
type IgnoreAPIRequest struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
Flag bool `json:"flag"`
|
||||
}
|
||||
type ApplyAPISyncRequest struct {
|
||||
NewAPIs []APIRequest `json:"newApis"`
|
||||
DeleteAPIs []APIRequest `json:"deleteApis"`
|
||||
}
|
||||
type PolicyPathRequest struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
type SetPolicyPathsRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
Infos []PolicyPathRequest `json:"casbinInfos"`
|
||||
}
|
||||
type GetPolicyPathsRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
|
||||
type APISyncResponse struct {
|
||||
NewAPIs []*APIResponse `json:"newApis"`
|
||||
DeleteAPIs []*APIResponse `json:"deleteApis"`
|
||||
IgnoreAPIs []*APIResponse `json:"ignoreApis"`
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package dto
|
||||
|
||||
type AuthorityRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
AuthorityName string `json:"authorityName"`
|
||||
ParentID *uint `json:"parentId"`
|
||||
DataScope int `json:"dataScope"`
|
||||
DefaultRouter string `json:"defaultRouter"`
|
||||
}
|
||||
|
||||
type CopyAuthorityRequest struct {
|
||||
Authority AuthorityRequest `json:"authority"`
|
||||
OldAuthorityID uint `json:"oldAuthorityId"`
|
||||
}
|
||||
|
||||
type DeleteAuthorityRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
type SetRoleUsersRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
UserIDs []uint `json:"userIds"`
|
||||
}
|
||||
type SetDataScopeRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
DataScope int `json:"dataScope"`
|
||||
DepartmentIDs []uint `json:"deptIds"`
|
||||
}
|
||||
|
||||
type AuthorityResponse struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
AuthorityName string `json:"authorityName"`
|
||||
ParentID *uint `json:"parentId"`
|
||||
DataScope int `json:"dataScope"`
|
||||
DefaultRouter string `json:"defaultRouter"`
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package dto
|
||||
|
||||
type SendEmailRequest struct {
|
||||
To string `json:"to"`
|
||||
Subject string `json:"subject"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package dto
|
||||
|
||||
type MenuMetaRequest struct {
|
||||
ActiveName string `json:"activeName"`
|
||||
KeepAlive bool `json:"keepAlive"`
|
||||
DefaultMenu bool `json:"defaultMenu"`
|
||||
Title string `json:"title"`
|
||||
Icon string `json:"icon"`
|
||||
CloseTab bool `json:"closeTab"`
|
||||
TransitionType string `json:"transitionType"`
|
||||
}
|
||||
|
||||
type MenuButtonRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"desc"`
|
||||
}
|
||||
|
||||
type MenuParameterRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Type string `json:"type"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type MenuRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
ParentID uint `json:"parentId"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Component string `json:"component"`
|
||||
Sort int `json:"sort"`
|
||||
Meta MenuMetaRequest `json:"meta"`
|
||||
MenuButtons []MenuButtonRequest `json:"menuBtn"`
|
||||
Parameters []MenuParameterRequest `json:"parameters"`
|
||||
}
|
||||
|
||||
type DeleteMenuRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
|
||||
type GetMenuRequest struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
||||
type AuthorityMenuItemRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
|
||||
type SetAuthorityMenusRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
Menus []AuthorityMenuItemRequest `json:"menus"`
|
||||
}
|
||||
|
||||
type GetAuthorityMenusRequest struct {
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
|
||||
type SetMenuRolesRequest struct {
|
||||
MenuID uint `json:"menuId"`
|
||||
AuthorityIDs []uint `json:"authorityIds"`
|
||||
}
|
||||
|
||||
type MenuMetaResponse struct {
|
||||
ActiveName string `json:"activeName"`
|
||||
KeepAlive bool `json:"keepAlive"`
|
||||
DefaultMenu bool `json:"defaultMenu"`
|
||||
Title string `json:"title"`
|
||||
Icon string `json:"icon"`
|
||||
CloseTab bool `json:"closeTab"`
|
||||
TransitionType string `json:"transitionType"`
|
||||
}
|
||||
|
||||
type MenuButtonResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"desc"`
|
||||
SysBaseMenuID uint `json:"sysBaseMenuID"`
|
||||
}
|
||||
|
||||
type MenuParameterResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
SysBaseMenuID uint `json:"SysBaseMenuID"`
|
||||
Type string `json:"type"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type MenuResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
ParentID uint `json:"parentId"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Component string `json:"component"`
|
||||
Sort int `json:"sort"`
|
||||
Meta MenuMetaResponse `json:"meta"`
|
||||
Children []*MenuResponse `json:"children"`
|
||||
Parameters []MenuParameterResponse `json:"parameters"`
|
||||
MenuButtons []MenuButtonResponse `json:"menuBtn"`
|
||||
Buttons map[string]uint `json:"btns"`
|
||||
}
|
||||
|
||||
type AuthorityMenuResponse struct {
|
||||
MenuID uint `json:"menuId"`
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
SysBaseMenu *MenuResponse `json:"sysBaseMenu"`
|
||||
ParentID uint `json:"parentId"`
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package dto
|
||||
|
||||
import "time"
|
||||
|
||||
type DepartmentRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
ParentID uint `json:"parentId"`
|
||||
Sort int `json:"sort"`
|
||||
LeaderID uint `json:"leaderId"`
|
||||
Status bool `json:"status"`
|
||||
}
|
||||
|
||||
type DepartmentListRequest struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type DeleteDepartmentRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
type SetDepartmentUsersRequest struct {
|
||||
DepartmentID uint `json:"deptId"`
|
||||
UserIDs []uint `json:"userIds"`
|
||||
}
|
||||
type SetUserDepartmentsRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
DepartmentIDs []uint `json:"deptIds"`
|
||||
Primary uint `json:"primaryDeptId"`
|
||||
}
|
||||
|
||||
type DepartmentResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
CreatedAt time.Time `json:"CreatedAt"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt"`
|
||||
DeletedAt any `json:"DeletedAt"`
|
||||
Name string `json:"name"`
|
||||
ParentID uint `json:"parentId"`
|
||||
Ancestors string `json:"ancestors"`
|
||||
Sort int `json:"sort"`
|
||||
LeaderID uint `json:"leaderId"`
|
||||
Leader any `json:"leader"`
|
||||
Status bool `json:"status"`
|
||||
Children []*DepartmentResponse `json:"children"`
|
||||
NamePath string `json:"namePath"`
|
||||
}
|
||||
|
||||
type PositionRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Sort int `json:"sort"`
|
||||
Status bool `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type PositionListRequest struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
type DeletePositionRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
type SetPositionUsersRequest struct {
|
||||
PositionID uint `json:"positionId"`
|
||||
UserIDs []uint `json:"userIds"`
|
||||
}
|
||||
type SetUserPositionsRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
PositionIDs []uint `json:"positionIds"`
|
||||
}
|
||||
|
||||
type PositionResponse struct {
|
||||
ID uint `json:"ID"`
|
||||
CreatedAt time.Time `json:"CreatedAt"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt"`
|
||||
DeletedAt any `json:"DeletedAt"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Sort int `json:"sort"`
|
||||
Status bool `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package dto
|
||||
|
||||
type GetAuthorityButtonsRequest struct {
|
||||
MenuID uint `json:"menuID"`
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
}
|
||||
|
||||
type SetAuthorityButtonsRequest struct {
|
||||
MenuID uint `json:"menuID"`
|
||||
AuthorityID uint `json:"authorityId"`
|
||||
Selected []uint `json:"selected"`
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package dto
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type TaskRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Spec string `json:"spec"`
|
||||
WithSeconds bool `json:"withSeconds"`
|
||||
ExecutorType string `json:"executorType"`
|
||||
MethodName string `json:"methodName"`
|
||||
Params json.RawMessage `json:"params"`
|
||||
HTTPURL string `json:"httpUrl"`
|
||||
HTTPMethod string `json:"httpMethod"`
|
||||
HTTPHeader json.RawMessage `json:"httpHeader"`
|
||||
HTTPBody string `json:"httpBody"`
|
||||
HTTPAllowPrivate bool `json:"httpAllowPrivate"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type DeleteTaskRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
}
|
||||
type ToggleTaskRequest struct {
|
||||
ID uint `json:"ID"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type MenuService struct{ uc *biz.MenuUsecase }
|
||||
|
||||
func NewMenuService(uc *biz.MenuUsecase) *MenuService { return &MenuService{uc: uc} }
|
||||
|
||||
func menuDomain(v *dto.MenuRequest) *biz.Menu {
|
||||
menu := &biz.Menu{ID: v.ID, ParentID: v.ParentID, Path: v.Path, Name: v.Name, Hidden: v.Hidden, Component: v.Component, Sort: v.Sort, ActiveName: v.Meta.ActiveName, KeepAlive: v.Meta.KeepAlive, DefaultMenu: v.Meta.DefaultMenu, Title: v.Meta.Title, Icon: v.Meta.Icon, CloseTab: v.Meta.CloseTab, TransitionType: v.Meta.TransitionType}
|
||||
menu.Buttons = make([]*biz.MenuButton, 0, len(v.MenuButtons))
|
||||
for _, button := range v.MenuButtons {
|
||||
menu.Buttons = append(menu.Buttons, &biz.MenuButton{ID: button.ID, Name: button.Name, Description: button.Description, MenuID: v.ID})
|
||||
}
|
||||
menu.Parameters = make([]*biz.MenuParameter, 0, len(v.Parameters))
|
||||
for _, parameter := range v.Parameters {
|
||||
menu.Parameters = append(menu.Parameters, &biz.MenuParameter{ID: parameter.ID, MenuID: v.ID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
|
||||
}
|
||||
return menu
|
||||
}
|
||||
|
||||
func menuResponse(menu *biz.Menu) *dto.MenuResponse {
|
||||
children := make([]*dto.MenuResponse, 0, len(menu.Children))
|
||||
for _, child := range menu.Children {
|
||||
children = append(children, menuResponse(child))
|
||||
}
|
||||
buttons := make([]dto.MenuButtonResponse, 0, len(menu.Buttons))
|
||||
buttonAuthorities := make(map[string]uint, len(menu.Buttons))
|
||||
for _, button := range menu.Buttons {
|
||||
buttons = append(buttons, dto.MenuButtonResponse{ID: button.ID, Name: button.Name, Description: button.Description, SysBaseMenuID: button.MenuID})
|
||||
if button.AuthorityID != 0 {
|
||||
buttonAuthorities[button.Name] = button.AuthorityID
|
||||
}
|
||||
}
|
||||
parameters := make([]dto.MenuParameterResponse, 0, len(menu.Parameters))
|
||||
for _, parameter := range menu.Parameters {
|
||||
parameters = append(parameters, dto.MenuParameterResponse{ID: parameter.ID, SysBaseMenuID: parameter.MenuID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value})
|
||||
}
|
||||
return &dto.MenuResponse{ID: menu.ID, ParentID: menu.ParentID, Path: menu.Path, Name: menu.Name, Hidden: menu.Hidden, Component: menu.Component, Sort: menu.Sort, Meta: dto.MenuMetaResponse{ActiveName: menu.ActiveName, KeepAlive: menu.KeepAlive, DefaultMenu: menu.DefaultMenu, Title: menu.Title, Icon: menu.Icon, CloseTab: menu.CloseTab, TransitionType: menu.TransitionType}, Children: children, Parameters: parameters, MenuButtons: buttons, Buttons: buttonAuthorities}
|
||||
}
|
||||
|
||||
func menuResponses(items []*biz.Menu) []*dto.MenuResponse {
|
||||
out := make([]*dto.MenuResponse, 0, len(items))
|
||||
for _, item := range items {
|
||||
out = append(out, menuResponse(item))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *MenuService) List(ctx context.Context) ([]*dto.MenuResponse, error) {
|
||||
items, err := s.uc.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menuResponses(items), nil
|
||||
}
|
||||
|
||||
func (s *MenuService) Tree(ctx context.Context) ([]*dto.MenuResponse, error) {
|
||||
items, err := s.uc.Tree(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menuResponses(items), nil
|
||||
}
|
||||
|
||||
func (s *MenuService) Create(ctx context.Context, req *dto.MenuRequest) error {
|
||||
return s.uc.Create(ctx, menuDomain(req))
|
||||
}
|
||||
func (s *MenuService) Update(ctx context.Context, req *dto.MenuRequest) error {
|
||||
return s.uc.Update(ctx, menuDomain(req))
|
||||
}
|
||||
func (s *MenuService) Delete(ctx context.Context, id uint) error { return s.uc.Delete(ctx, id) }
|
||||
|
||||
func (s *MenuService) Find(ctx context.Context, id uint) (*dto.MenuResponse, error) {
|
||||
item, err := s.uc.Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menuResponse(item), nil
|
||||
}
|
||||
|
||||
func (s *MenuService) SetAuthorityMenus(ctx context.Context, req *dto.SetAuthorityMenusRequest) error {
|
||||
ids := make([]uint, 0, len(req.Menus))
|
||||
for _, menu := range req.Menus {
|
||||
ids = append(ids, menu.ID)
|
||||
}
|
||||
return s.uc.SetAuthorityMenus(ctx, req.AuthorityID, ids)
|
||||
}
|
||||
|
||||
func (s *MenuService) AuthorityMenus(ctx context.Context, authorityID uint) ([]*dto.AuthorityMenuResponse, error) {
|
||||
items, err := s.uc.AuthorityMenus(ctx, authorityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]*dto.AuthorityMenuResponse, 0, len(items))
|
||||
for _, item := range items {
|
||||
out = append(out, &dto.AuthorityMenuResponse{MenuID: item.ID, AuthorityID: authorityID, SysBaseMenu: menuResponse(item), ParentID: item.ParentID})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *MenuService) RoleIDs(ctx context.Context, menuID uint) ([]uint, error) {
|
||||
return s.uc.RoleIDs(ctx, menuID)
|
||||
}
|
||||
func (s *MenuService) SetRoles(ctx context.Context, req *dto.SetMenuRolesRequest) error {
|
||||
return s.uc.SetRoles(ctx, req.MenuID, req.AuthorityIDs)
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type OrganizationService struct{ uc *biz.OrganizationUsecase }
|
||||
|
||||
func NewOrganizationService(uc *biz.OrganizationUsecase) *OrganizationService {
|
||||
return &OrganizationService{uc: uc}
|
||||
}
|
||||
|
||||
func departmentResponse(value *biz.Department) *dto.DepartmentResponse {
|
||||
children := make([]*dto.DepartmentResponse, 0, len(value.Children))
|
||||
for _, child := range value.Children {
|
||||
children = append(children, departmentResponse(child))
|
||||
}
|
||||
return &dto.DepartmentResponse{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: nil, Name: value.Name, ParentID: value.ParentID, Ancestors: value.Ancestors, Sort: value.Sort, LeaderID: value.LeaderID, Leader: nil, Status: value.Status, Children: children, NamePath: ""}
|
||||
}
|
||||
|
||||
func departmentDomain(value *dto.DepartmentRequest) *biz.Department {
|
||||
return &biz.Department{ID: value.ID, Name: value.Name, ParentID: value.ParentID, Sort: value.Sort, LeaderID: value.LeaderID, Status: value.Status}
|
||||
}
|
||||
|
||||
func (s *OrganizationService) Departments(ctx context.Context, name string) ([]*dto.DepartmentResponse, error) {
|
||||
items, err := s.uc.Departments(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]*dto.DepartmentResponse, 0, len(items))
|
||||
for _, item := range items {
|
||||
out = append(out, departmentResponse(item))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
func (s *OrganizationService) CreateDepartment(ctx context.Context, req *dto.DepartmentRequest) error {
|
||||
return s.uc.CreateDepartment(ctx, departmentDomain(req))
|
||||
}
|
||||
func (s *OrganizationService) UpdateDepartment(ctx context.Context, req *dto.DepartmentRequest) error {
|
||||
return s.uc.UpdateDepartment(ctx, departmentDomain(req))
|
||||
}
|
||||
func (s *OrganizationService) DeleteDepartment(ctx context.Context, id uint) error {
|
||||
return s.uc.DeleteDepartment(ctx, id)
|
||||
}
|
||||
func (s *OrganizationService) Department(ctx context.Context, id uint) (*dto.DepartmentResponse, error) {
|
||||
value, err := s.uc.Department(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return departmentResponse(value), nil
|
||||
}
|
||||
func (s *OrganizationService) DepartmentUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return s.uc.DepartmentUserIDs(ctx, id)
|
||||
}
|
||||
func (s *OrganizationService) SetDepartmentUsers(ctx context.Context, req *dto.SetDepartmentUsersRequest) error {
|
||||
return s.uc.SetDepartmentUsers(ctx, req.DepartmentID, req.UserIDs)
|
||||
}
|
||||
func (s *OrganizationService) SetUserDepartments(ctx context.Context, req *dto.SetUserDepartmentsRequest) error {
|
||||
return s.uc.SetUserDepartments(ctx, req.ID, req.DepartmentIDs, req.Primary)
|
||||
}
|
||||
|
||||
func positionDomain(value *dto.PositionRequest) *biz.Position {
|
||||
return &biz.Position{ID: value.ID, Name: value.Name, Code: value.Code, Sort: value.Sort, Status: value.Status, Remark: value.Remark}
|
||||
}
|
||||
func positionResponse(value *biz.Position) *dto.PositionResponse {
|
||||
return &dto.PositionResponse{ID: value.ID, CreatedAt: value.CreatedAt, UpdatedAt: value.UpdatedAt, DeletedAt: nil, Name: value.Name, Code: value.Code, Sort: value.Sort, Status: value.Status, Remark: value.Remark}
|
||||
}
|
||||
func (s *OrganizationService) Positions(ctx context.Context, req *dto.PositionListRequest) ([]*dto.PositionResponse, int64, error) {
|
||||
items, total, err := s.uc.Positions(ctx, req.Page, req.PageSize, &biz.Position{Name: req.Name, Code: req.Code})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
out := make([]*dto.PositionResponse, 0, len(items))
|
||||
for _, item := range items {
|
||||
out = append(out, positionResponse(item))
|
||||
}
|
||||
return out, total, nil
|
||||
}
|
||||
func (s *OrganizationService) CreatePosition(ctx context.Context, req *dto.PositionRequest) error {
|
||||
return s.uc.CreatePosition(ctx, positionDomain(req))
|
||||
}
|
||||
func (s *OrganizationService) UpdatePosition(ctx context.Context, req *dto.PositionRequest) error {
|
||||
return s.uc.UpdatePosition(ctx, positionDomain(req))
|
||||
}
|
||||
func (s *OrganizationService) DeletePosition(ctx context.Context, id uint) error {
|
||||
return s.uc.DeletePosition(ctx, id)
|
||||
}
|
||||
func (s *OrganizationService) Position(ctx context.Context, id uint) (*dto.PositionResponse, error) {
|
||||
value, err := s.uc.Position(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return positionResponse(value), nil
|
||||
}
|
||||
func (s *OrganizationService) PositionUserIDs(ctx context.Context, id uint) ([]uint, error) {
|
||||
return s.uc.PositionUserIDs(ctx, id)
|
||||
}
|
||||
func (s *OrganizationService) SetPositionUsers(ctx context.Context, req *dto.SetPositionUsersRequest) error {
|
||||
return s.uc.SetPositionUsers(ctx, req.PositionID, req.UserIDs)
|
||||
}
|
||||
func (s *OrganizationService) SetUserPositions(ctx context.Context, req *dto.SetUserPositionsRequest) error {
|
||||
return s.uc.SetUserPositions(ctx, req.ID, req.PositionIDs)
|
||||
}
|
||||
|
|
@ -3,4 +3,4 @@ package service
|
|||
import "github.com/google/wire"
|
||||
|
||||
// ProviderSet is service providers.
|
||||
var ProviderSet = wire.NewSet(NewSystemService, NewAccessService, NewSettingsService, NewVersionService, NewExportService, NewAuditService, NewTaskService, NewMediaService, NewAnnouncementService, NewEmailService)
|
||||
var ProviderSet = wire.NewSet(NewSystemService, NewAccessService, NewMenuService, NewOrganizationService, NewSettingsService, NewVersionService, NewExportService, NewAuditService, NewTaskService, NewMediaService, NewAnnouncementService, NewEmailService)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"io"
|
||||
"kra/internal/biz"
|
||||
"kra/internal/conf"
|
||||
"kra/internal/service/dto"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
|
@ -26,6 +27,22 @@ type TaskService struct {
|
|||
func NewTaskService(uc *biz.TaskUsecase, media *biz.MediaUsecase, config *conf.AdminBackend) *TaskService {
|
||||
return &TaskService{uc: uc, media: media, config: config}
|
||||
}
|
||||
func taskDomain(v *dto.TaskRequest) *biz.TimedTask {
|
||||
return &biz.TimedTask{ID: v.ID, Name: v.Name, Description: v.Description, Spec: v.Spec, WithSeconds: v.WithSeconds, ExecutorType: v.ExecutorType, MethodName: v.MethodName, Params: v.Params, HTTPURL: v.HTTPURL, HTTPMethod: v.HTTPMethod, HTTPHeader: v.HTTPHeader, HTTPBody: v.HTTPBody, HTTPAllowPrivate: v.HTTPAllowPrivate, Enabled: v.Enabled}
|
||||
}
|
||||
func (s *TaskService) CreateRequest(ctx context.Context, req *dto.TaskRequest) (uint, error) {
|
||||
value := taskDomain(req)
|
||||
if err := s.Create(ctx, value); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return value.ID, nil
|
||||
}
|
||||
func (s *TaskService) UpdateRequest(ctx context.Context, req *dto.TaskRequest) error {
|
||||
return s.Update(ctx, taskDomain(req))
|
||||
}
|
||||
func (s *TaskService) ListRequest(ctx context.Context, page, size int, name, executorType string, enabled *bool, next map[uint]time.Time) ([]map[string]any, int64, error) {
|
||||
return s.Tasks(ctx, page, size, &biz.TimedTask{Name: name, ExecutorType: executorType, EnabledFilter: enabled}, next)
|
||||
}
|
||||
func (s *TaskService) Validate(v *biz.TimedTask) error {
|
||||
if v.Name == "" {
|
||||
return errors.New("任务名不能为空")
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
package server
|
||||
package worker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/service"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
type TaskScheduler struct {
|
||||
|
|
@ -22,6 +24,7 @@ type TaskScheduler struct {
|
|||
subMu sync.RWMutex
|
||||
subscribers map[chan []byte]struct{}
|
||||
}
|
||||
|
||||
type scheduledEntry struct {
|
||||
seconds bool
|
||||
entry cron.EntryID
|
||||
|
|
@ -30,6 +33,7 @@ type scheduledEntry struct {
|
|||
func NewTaskScheduler(service *service.TaskService, logger *slog.Logger) *TaskScheduler {
|
||||
return &TaskScheduler{service: service, logger: logger, standard: cron.New(), seconds: cron.New(cron.WithSeconds()), entries: map[uint]scheduledEntry{}, subscribers: map[chan []byte]struct{}{}}
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) Start(ctx context.Context) error {
|
||||
s.standard.Start()
|
||||
s.seconds.Start()
|
||||
|
|
@ -49,9 +53,9 @@ func (s *TaskScheduler) Start(ctx context.Context) error {
|
|||
<-ctx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) Stop(ctx context.Context) error {
|
||||
standardDone := s.standard.Stop().Done()
|
||||
secondsDone := s.seconds.Stop().Done()
|
||||
standardDone, secondsDone := s.standard.Stop().Done(), s.seconds.Stop().Done()
|
||||
select {
|
||||
case <-standardDone:
|
||||
case <-ctx.Done():
|
||||
|
|
@ -64,6 +68,7 @@ func (s *TaskScheduler) Stop(ctx context.Context) error {
|
|||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) Remove(id uint) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
|
@ -76,6 +81,7 @@ func (s *TaskScheduler) Remove(id uint) {
|
|||
delete(s.entries, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) Reload(ctx context.Context) error {
|
||||
s.mu.Lock()
|
||||
for id, old := range s.entries {
|
||||
|
|
@ -105,6 +111,7 @@ func (s *TaskScheduler) Reload(ctx context.Context) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) Schedule(task *biz.TimedTask) error {
|
||||
s.Remove(task.ID)
|
||||
if !task.Enabled {
|
||||
|
|
@ -132,6 +139,24 @@ func (s *TaskScheduler) Schedule(task *biz.TimedTask) error {
|
|||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) ScheduleID(ctx context.Context, id uint) error {
|
||||
task, err := s.service.Task(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Schedule(task)
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) TriggerID(ctx context.Context, id uint) error {
|
||||
task, err := s.service.Task(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Trigger(task)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) NextRuns() map[uint]time.Time {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
|
@ -145,6 +170,7 @@ func (s *TaskScheduler) NextRuns() map[uint]time.Time {
|
|||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) Trigger(task *biz.TimedTask) {
|
||||
go func() {
|
||||
log := s.service.Run(context.Background(), task, "manual")
|
||||
|
|
@ -153,6 +179,7 @@ func (s *TaskScheduler) Trigger(task *biz.TimedTask) {
|
|||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) Subscribe() chan []byte {
|
||||
ch := make(chan []byte, 16)
|
||||
s.subMu.Lock()
|
||||
Loading…
Reference in New Issue