502 lines
11 KiB
Go
502 lines
11 KiB
Go
package admin
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"jiacrontab/models"
|
|
"jiacrontab/pkg/proto"
|
|
"jiacrontab/pkg/util"
|
|
"jiacrontab/pkg/version"
|
|
"strings"
|
|
"time"
|
|
|
|
jwt "github.com/dgrijalva/jwt-go"
|
|
)
|
|
|
|
type CustomerClaims struct {
|
|
jwt.StandardClaims
|
|
Version int64
|
|
UserID uint
|
|
Mail string
|
|
Username string
|
|
GroupID uint
|
|
Root bool
|
|
}
|
|
|
|
// Login 用户登录
|
|
func Login(ctx *myctx) {
|
|
var (
|
|
err error
|
|
reqBody LoginReqParams
|
|
user models.User
|
|
customerClaims CustomerClaims
|
|
cfg = ctx.adm.getOpts()
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
return
|
|
}
|
|
|
|
if reqBody.IsLdap {
|
|
luser, err := ctx.adm.ldap.Login(reqBody.Username, reqBody.Passwd)
|
|
if err != nil {
|
|
ctx.respAuthFailed(err)
|
|
return
|
|
}
|
|
user = *luser
|
|
} else {
|
|
if !user.Verify(reqBody.Username, reqBody.Passwd) {
|
|
ctx.respAuthFailed(errors.New("帐号或密码不正确"))
|
|
return
|
|
}
|
|
}
|
|
|
|
customerClaims.ExpiresAt = cfg.Jwt.Expires + time.Now().Unix()
|
|
customerClaims.Username = reqBody.Username
|
|
customerClaims.UserID = user.ID
|
|
customerClaims.Mail = user.Mail
|
|
customerClaims.GroupID = user.GroupID
|
|
customerClaims.Root = user.Root
|
|
customerClaims.Version = user.Version
|
|
|
|
if reqBody.Remember {
|
|
customerClaims.ExpiresAt = time.Now().Add(24 * 30 * time.Hour).Unix()
|
|
}
|
|
|
|
token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, customerClaims).SignedString([]byte(cfg.Jwt.SigningKey))
|
|
|
|
if err != nil {
|
|
ctx.respAuthFailed(errors.New("无法生成访问凭证"))
|
|
return
|
|
}
|
|
|
|
ctx.respSucc("", map[string]interface{}{
|
|
"token": token,
|
|
"groupID": user.GroupID,
|
|
"root": user.Root,
|
|
"mail": user.Mail,
|
|
"username": user.Username,
|
|
"userID": user.ID,
|
|
})
|
|
}
|
|
|
|
func GetActivityList(ctx *myctx) {
|
|
var (
|
|
err error
|
|
reqBody ReadMoreReqParams
|
|
events []models.Event
|
|
isSuper bool
|
|
model = models.DB()
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
return
|
|
}
|
|
|
|
if ctx.isSuper() {
|
|
isSuper = true
|
|
}
|
|
|
|
if reqBody.LastID == 0 {
|
|
if !isSuper {
|
|
model = model.Where("group_id=?", ctx.claims.GroupID)
|
|
}
|
|
|
|
} else {
|
|
if !isSuper {
|
|
model = model.Where("group_id=? and id<?", ctx.claims.GroupID, reqBody.LastID)
|
|
} else {
|
|
model = model.Where("id<?", reqBody.LastID)
|
|
}
|
|
}
|
|
if reqBody.Keywords != "" {
|
|
txt := "%" + reqBody.Keywords + "%"
|
|
model = model.Where(`(
|
|
username like ? or
|
|
event_desc like ? or
|
|
target_name like ? or
|
|
source_username like ? or
|
|
source_name like ? or
|
|
content like ?)`, txt, txt, txt, txt, txt, txt)
|
|
}
|
|
err = model.Order(fmt.Sprintf("created_at %s", reqBody.Orderby)).
|
|
Limit(reqBody.Pagesize).
|
|
Find(&events).Error
|
|
|
|
if err != nil && err != sql.ErrNoRows {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
|
|
ctx.respSucc("", map[string]interface{}{
|
|
"list": events,
|
|
"pagesize": reqBody.Pagesize,
|
|
})
|
|
}
|
|
|
|
func GetJobHistory(ctx *myctx) {
|
|
var (
|
|
err error
|
|
reqBody ReadMoreReqParams
|
|
historys []models.JobHistory
|
|
addrs []string
|
|
model = models.DB()
|
|
isSuper = ctx.isSuper()
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
return
|
|
}
|
|
|
|
if addrs, err = ctx.getGroupAddr(); err != nil {
|
|
ctx.respError(proto.Code_Error, err.Error(), err)
|
|
return
|
|
}
|
|
|
|
if reqBody.Keywords != "" {
|
|
txt := "%" + reqBody.Keywords + "%"
|
|
model = model.Where("(job_name like ? or addr like ? or exit_msg like ?)",
|
|
txt, txt, txt)
|
|
}
|
|
|
|
if reqBody.LastID == 0 {
|
|
if !isSuper {
|
|
model = model.Where("addr in (?)", addrs)
|
|
}
|
|
|
|
err = model.Order(fmt.Sprintf("created_at %s", reqBody.Orderby)).
|
|
Limit(reqBody.Pagesize).
|
|
Find(&historys).Error
|
|
} else {
|
|
if !isSuper {
|
|
model = model.Where("addr in (?) and id<?", addrs, reqBody.LastID)
|
|
} else {
|
|
model = model.Where("id<?", reqBody.LastID)
|
|
}
|
|
err = model.Where("addr in (?) and id<?", addrs, reqBody.LastID).
|
|
Order(fmt.Sprintf("created_at %s", reqBody.Orderby)).
|
|
Limit(reqBody.Pagesize).
|
|
Find(&historys).Error
|
|
}
|
|
|
|
if err != nil && err != sql.ErrNoRows {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
|
|
ctx.respSucc("", map[string]interface{}{
|
|
"list": historys,
|
|
"pagesize": reqBody.Pagesize,
|
|
})
|
|
}
|
|
|
|
func AuditJob(ctx *myctx) {
|
|
var (
|
|
err error
|
|
reqBody AuditJobReqParams
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
return
|
|
}
|
|
|
|
if !ctx.verifyNodePermission(reqBody.Addr) {
|
|
ctx.respNotAllowed()
|
|
return
|
|
}
|
|
|
|
if ctx.claims.GroupID != models.SuperGroup.ID && !ctx.claims.Root {
|
|
ctx.respNotAllowed()
|
|
return
|
|
}
|
|
|
|
if reqBody.JobType == "crontab" {
|
|
var reply []models.CrontabJob
|
|
if err = rpcCall(reqBody.Addr, "CrontabJob.Audit", proto.AuditJobArgs{
|
|
Root: ctx.claims.Root,
|
|
GroupID: ctx.claims.GroupID,
|
|
JobIDs: reqBody.JobIDs,
|
|
}, &reply); err != nil {
|
|
ctx.respRPCError(err)
|
|
return
|
|
}
|
|
var targetNames []string
|
|
for _, v := range reply {
|
|
targetNames = append(targetNames, v.Name)
|
|
}
|
|
ctx.pubEvent(strings.Join(targetNames, ","), event_AuditCrontabJob, models.EventSourceName(reqBody.Addr), reqBody)
|
|
} else {
|
|
var reply []models.DaemonJob
|
|
if err = rpcCall(reqBody.Addr, "DaemonJob.Audit", proto.AuditJobArgs{
|
|
Root: ctx.claims.Root,
|
|
GroupID: ctx.claims.GroupID,
|
|
JobIDs: reqBody.JobIDs,
|
|
}, &reply); err != nil {
|
|
ctx.respRPCError(err)
|
|
return
|
|
}
|
|
var targetNames []string
|
|
for _, v := range reply {
|
|
targetNames = append(targetNames, v.Name)
|
|
}
|
|
ctx.pubEvent(strings.Join(targetNames, ","), event_AuditDaemonJob, models.EventSourceName(reqBody.Addr), reqBody)
|
|
}
|
|
|
|
ctx.respSucc("", nil)
|
|
}
|
|
|
|
// Signup 注册新用户
|
|
func Signup(ctx *myctx) {
|
|
var (
|
|
err error
|
|
user models.User
|
|
reqBody UserReqParams
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
return
|
|
}
|
|
|
|
if !ctx.isSuper() {
|
|
ctx.respNotAllowed()
|
|
return
|
|
}
|
|
|
|
if reqBody.GroupName != "" {
|
|
group := models.Group{
|
|
Name: reqBody.GroupName,
|
|
}
|
|
if err = models.DB().Save(&group).Error; err != nil {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
reqBody.GroupID = group.ID
|
|
}
|
|
|
|
user.Username = reqBody.Username
|
|
user.Passwd = reqBody.Passwd
|
|
user.GroupID = reqBody.GroupID
|
|
user.Root = reqBody.Root
|
|
user.Avatar = reqBody.Avatar
|
|
user.Mail = reqBody.Mail
|
|
reqBody.Passwd = ""
|
|
if user.GroupID == models.SuperGroup.ID {
|
|
user.Root = true
|
|
}
|
|
|
|
if err = user.Create(); err != nil {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
|
|
ctx.pubEvent(user.Username, event_SignUpUser, "", reqBody)
|
|
ctx.respSucc("", true)
|
|
}
|
|
|
|
func EditUser(ctx *myctx) {
|
|
var (
|
|
err error
|
|
user models.User
|
|
reqBody EditUserReqParams
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
return
|
|
}
|
|
|
|
// change password
|
|
if reqBody.OldPwd != "" && reqBody.Passwd != "" {
|
|
if !user.VerifyByUserId(reqBody.UserID, reqBody.OldPwd) {
|
|
ctx.respParamError(errors.New("密码错误"))
|
|
return
|
|
}
|
|
}
|
|
|
|
user.ID = reqBody.UserID
|
|
user.Passwd = reqBody.Passwd
|
|
user.Avatar = reqBody.Avatar
|
|
user.Mail = reqBody.Mail
|
|
|
|
if err = user.Update(); err != nil {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
|
|
ctx.pubEvent(user.Username, event_EditUser, "", reqBody)
|
|
ctx.respSucc("", true)
|
|
}
|
|
|
|
func DeleteUser(ctx *myctx) {
|
|
var (
|
|
err error
|
|
user models.User
|
|
reqBody DeleteUserReqParams
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
return
|
|
}
|
|
|
|
if !ctx.isSuper() {
|
|
ctx.respNotAllowed()
|
|
return
|
|
}
|
|
user.ID = reqBody.UserID
|
|
if err = user.Delete(); err != nil {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
ctx.pubEvent(user.Username, event_DeleteUser, "", reqBody)
|
|
ctx.respSucc("", true)
|
|
}
|
|
|
|
// UserStat 统计信息
|
|
func UserStat(ctx *myctx) {
|
|
var (
|
|
err error
|
|
auditNumStat struct {
|
|
CrontabJobAuditNum uint
|
|
DaemonJobAuditNum uint
|
|
CrontabJobFailNum uint
|
|
DaemonTaskNum uint
|
|
CrontabTaskNum uint
|
|
NodeNum uint
|
|
}
|
|
cfg = ctx.adm.getOpts()
|
|
)
|
|
|
|
err = models.DB().Raw(
|
|
`select
|
|
sum(crontab_job_audit_num) as crontab_job_audit_num,
|
|
sum(daemon_job_audit_num) as daemon_job_audit_num,
|
|
sum(crontab_job_fail_num) as crontab_job_fail_num,
|
|
sum(daemon_task_num) as daemon_task_num,
|
|
sum(crontab_task_num) as crontab_task_num,
|
|
count(*) as node_num
|
|
from nodes
|
|
where group_id=? and deleted_at is null`, ctx.claims.GroupID).Scan(&auditNumStat).Error
|
|
if err != nil {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
|
|
ctx.respSucc("", map[string]interface{}{
|
|
"systemInfo": util.SystemInfo(cfg.ServerStartTime),
|
|
"auditStat": auditNumStat,
|
|
"version": version.String(cfg.App.AppName),
|
|
})
|
|
}
|
|
|
|
// GroupUser 超级管理员设置普通用户分组
|
|
func GroupUser(ctx *myctx) {
|
|
var (
|
|
reqBody SetGroupReqParams
|
|
err error
|
|
user models.User
|
|
group models.Group
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respBasicError(err)
|
|
return
|
|
}
|
|
|
|
if !ctx.isSuper() {
|
|
ctx.respNotAllowed()
|
|
return
|
|
}
|
|
|
|
if reqBody.TargetGroupName != "" {
|
|
group.Name = reqBody.TargetGroupName
|
|
if err = models.DB().Save(&group).Error; err != nil {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
reqBody.TargetGroupID = group.ID
|
|
}
|
|
|
|
user.ID = reqBody.UserID
|
|
user.GroupID = reqBody.TargetGroupID
|
|
|
|
if reqBody.TargetGroupID == models.SuperGroup.ID {
|
|
user.Root = true
|
|
} else {
|
|
user.Root = reqBody.Root
|
|
}
|
|
|
|
if err = user.SetGroup(&group); err != nil {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
|
|
ctx.pubEvent(group.Name, event_GroupUser, models.EventSourceUsername(user.Username), reqBody)
|
|
ctx.respSucc("", nil)
|
|
}
|
|
|
|
// GetUserList 获得用户列表
|
|
// 支持获得全部用户,所属分组用户,指定分组用户(超级管理员)
|
|
func GetUserList(ctx *myctx) {
|
|
var (
|
|
reqBody GetUsersParams
|
|
userList []models.User
|
|
err error
|
|
total int64
|
|
)
|
|
|
|
if err = ctx.Valid(&reqBody); err != nil {
|
|
ctx.respParamError(err)
|
|
}
|
|
|
|
if reqBody.IsAll && ctx.claims.GroupID != models.SuperGroup.ID {
|
|
ctx.respNotAllowed()
|
|
return
|
|
}
|
|
|
|
if !reqBody.IsAll && reqBody.QueryGroupID != ctx.claims.GroupID && ctx.claims.GroupID != models.SuperGroup.ID {
|
|
ctx.respNotAllowed()
|
|
return
|
|
}
|
|
|
|
if reqBody.QueryGroupID == 0 {
|
|
reqBody.QueryGroupID = ctx.claims.GroupID
|
|
}
|
|
|
|
m := models.DB().Model(&models.User{})
|
|
if reqBody.IsAll {
|
|
err = m.Where("username like ?", "%"+reqBody.SearchTxt+"%").Count(&total).Error
|
|
} else {
|
|
err = m.Where("group_id=? and username like ?", reqBody.QueryGroupID, "%"+reqBody.SearchTxt+"%").Count(&total).Error
|
|
}
|
|
|
|
if err != nil && err != sql.ErrNoRows {
|
|
ctx.respBasicError(err)
|
|
return
|
|
}
|
|
|
|
if reqBody.IsAll {
|
|
err = models.DB().Preload("Group").Where("username like ?", "%"+reqBody.SearchTxt+"%").Order("id desc").Offset((reqBody.Page - 1) * reqBody.Pagesize).Limit(reqBody.Pagesize).Find(&userList).Error
|
|
} else {
|
|
err = models.DB().Preload("Group").Where("group_id=? and username like ?", reqBody.QueryGroupID, "%"+reqBody.SearchTxt+"%").Offset((reqBody.Page - 1) * reqBody.Pagesize).Limit(reqBody.Pagesize).Find(&userList).Error
|
|
}
|
|
|
|
if err != nil && err != sql.ErrNoRows {
|
|
ctx.respDBError(err)
|
|
return
|
|
}
|
|
|
|
ctx.respSucc("", map[string]interface{}{
|
|
"list": userList,
|
|
"total": total,
|
|
"page": reqBody.Page,
|
|
"pagesize": reqBody.Pagesize,
|
|
})
|
|
}
|