mirror of
https://github.com/ccfos/nightingale.git
synced 2026-03-02 22:19:10 +00:00
Compare commits
7 Commits
v8.2.2
...
stable-052
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47898bf2e7 | ||
|
|
fe220c8d91 | ||
|
|
5dcb86ba06 | ||
|
|
744f4ca724 | ||
|
|
3fff1e820a | ||
|
|
bd2a67e1f7 | ||
|
|
48daa857da |
@@ -272,7 +272,7 @@ func (rt *Router) boardGetsByGids(c *gin.Context) {
|
||||
ginx.Dangerous(err)
|
||||
|
||||
if len(gids) == 0 {
|
||||
ginx.Bomb(http.StatusForbidden, "forbidden")
|
||||
ginx.NewRender(c).Data([]int{}, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func (rt *Router) loginPost(c *gin.Context) {
|
||||
var err error
|
||||
lc := rt.Sso.LDAP.Copy()
|
||||
if lc.Enable {
|
||||
user, err = ldapx.LdapLogin(rt.Ctx, f.Username, authPassWord, lc.DefaultRoles, lc)
|
||||
user, err = ldapx.LdapLogin(rt.Ctx, f.Username, authPassWord, lc.DefaultRoles, lc.DefaultTeams, lc)
|
||||
if err != nil {
|
||||
logger.Debugf("ldap login failed: %v username: %s", err, f.Username)
|
||||
var errLoginInN9e error
|
||||
|
||||
@@ -143,6 +143,8 @@ func (rt *Router) user() gin.HandlerFunc {
|
||||
|
||||
c.Set("user", user)
|
||||
c.Set("isadmin", user.IsAdmin())
|
||||
// Update user.LastActiveTime
|
||||
rt.UserCache.SetLastActiveTime(user.Id, time.Now().Unix())
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,13 +40,17 @@ func (rt *Router) userFindAll(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (rt *Router) userGets(c *gin.Context) {
|
||||
stime, etime := getTimeRange(c)
|
||||
limit := ginx.QueryInt(c, "limit", 20)
|
||||
query := ginx.QueryStr(c, "query", "")
|
||||
order := ginx.QueryStr(c, "order", "username")
|
||||
desc := ginx.QueryBool(c, "desc", false)
|
||||
|
||||
total, err := models.UserTotal(rt.Ctx, query)
|
||||
rt.UserCache.UpdateUsersLastActiveTime()
|
||||
total, err := models.UserTotal(rt.Ctx, query, stime, etime)
|
||||
ginx.Dangerous(err)
|
||||
|
||||
list, err := models.UserGets(rt.Ctx, query, limit, ginx.Offset(c, limit))
|
||||
list, err := models.UserGets(rt.Ctx, query, limit, ginx.Offset(c, limit), stime, etime, order, desc)
|
||||
ginx.Dangerous(err)
|
||||
|
||||
user := c.MustGet("user").(*models.User)
|
||||
|
||||
@@ -129,6 +129,7 @@ func (uc *UserCacheType) SyncUsers() {
|
||||
}
|
||||
|
||||
go uc.loopSyncUsers()
|
||||
go uc.loopUpdateLastActiveTime()
|
||||
}
|
||||
|
||||
func (uc *UserCacheType) loopSyncUsers() {
|
||||
@@ -194,3 +195,56 @@ func (uc *UserCacheType) syncUsers() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uc *UserCacheType) SetLastActiveTime(userId int64, lastActiveTime int64) {
|
||||
uc.Lock()
|
||||
defer uc.Unlock()
|
||||
if user, exists := uc.users[userId]; exists {
|
||||
user.LastActiveTime = lastActiveTime
|
||||
}
|
||||
}
|
||||
|
||||
func (uc *UserCacheType) loopUpdateLastActiveTime() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logger.Errorf("panic to loopUpdateLastActiveTime(), err: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
// Sync every five minutes
|
||||
duration := 5 * time.Minute
|
||||
for {
|
||||
time.Sleep(duration)
|
||||
if err := uc.UpdateUsersLastActiveTime(); err != nil {
|
||||
logger.Warningf("failed to update users' last active time: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (uc *UserCacheType) UpdateUsersLastActiveTime() error {
|
||||
// read the full list of users from the database
|
||||
users, err := models.UserGetAll(uc.ctx)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed to get all users from database")
|
||||
}
|
||||
|
||||
for _, dbUser := range users {
|
||||
cacheUser := uc.GetByUserId(dbUser.Id)
|
||||
|
||||
if cacheUser == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if dbUser.LastActiveTime >= cacheUser.LastActiveTime {
|
||||
continue
|
||||
}
|
||||
|
||||
err = models.UpdateUserLastActiveTime(uc.ctx, cacheUser.Id, cacheUser.LastActiveTime)
|
||||
if err != nil {
|
||||
logger.Warningf("failed to update last active time for user %d: %v", cacheUser.Id, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -230,7 +230,8 @@ type BoardBusigroup struct {
|
||||
}
|
||||
|
||||
type Users struct {
|
||||
Belong string `gorm:"column:belong;varchar(16);default:'';comment:belong"`
|
||||
Belong string `gorm:"column:belong;varchar(16);default:'';comment:belong"`
|
||||
LastActiveTime int64 `gorm:"column:last_active_time;type:int;default:0;comment:last_active_time"`
|
||||
}
|
||||
|
||||
type SsoConfig struct {
|
||||
|
||||
@@ -40,26 +40,27 @@ var (
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id int64 `json:"id" gorm:"primaryKey"`
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Password string `json:"-"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Portrait string `json:"portrait"`
|
||||
Roles string `json:"-"` // 这个字段写入数据库
|
||||
RolesLst []string `json:"roles" gorm:"-"` // 这个字段和前端交互
|
||||
TeamsLst []int64 `json:"-" gorm:"-"` // 这个字段方便映射团队,前端和数据库都不用到
|
||||
Contacts ormx.JSONObj `json:"contacts"` // 内容为 map[string]string 结构
|
||||
Maintainer int `json:"maintainer"` // 是否给管理员发消息 0:not send 1:send
|
||||
CreateAt int64 `json:"create_at"`
|
||||
CreateBy string `json:"create_by"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
UpdateBy string `json:"update_by"`
|
||||
Belong string `json:"belong"`
|
||||
Admin bool `json:"admin" gorm:"-"` // 方便前端使用
|
||||
UserGroupsRes []*UserGroupRes `json:"user_groups" gorm:"-"`
|
||||
BusiGroupsRes []*BusiGroupRes `json:"busi_groups" gorm:"-"`
|
||||
Id int64 `json:"id" gorm:"primaryKey"`
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Password string `json:"-"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Portrait string `json:"portrait"`
|
||||
Roles string `json:"-"` // 这个字段写入数据库
|
||||
RolesLst []string `json:"roles" gorm:"-"` // 这个字段和前端交互
|
||||
TeamsLst []int64 `json:"-" gorm:"-"` // 这个字段方便映射团队,前端和数据库都不用到
|
||||
Contacts ormx.JSONObj `json:"contacts"` // 内容为 map[string]string 结构
|
||||
Maintainer int `json:"maintainer"` // 是否给管理员发消息 0:not send 1:send
|
||||
CreateAt int64 `json:"create_at"`
|
||||
CreateBy string `json:"create_by"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
UpdateBy string `json:"update_by"`
|
||||
Belong string `json:"belong"`
|
||||
Admin bool `json:"admin" gorm:"-"` // 方便前端使用
|
||||
UserGroupsRes []*UserGroupRes `json:"user_groups" gorm:"-"`
|
||||
BusiGroupsRes []*BusiGroupRes `json:"busi_groups" gorm:"-"`
|
||||
LastActiveTime int64 `json:"last_active_time"`
|
||||
}
|
||||
|
||||
type UserGroupRes struct {
|
||||
@@ -194,8 +195,10 @@ func (u *User) Add(ctx *ctx.Context) error {
|
||||
}
|
||||
|
||||
func (u *User) Update(ctx *ctx.Context, selectField interface{}, selectFields ...interface{}) error {
|
||||
if err := u.Verify(); err != nil {
|
||||
return err
|
||||
if u.Belong == "" {
|
||||
if err := u.Verify(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return DB(ctx).Model(u).Select(selectField, selectFields...).Updates(u).Error
|
||||
@@ -218,6 +221,13 @@ func (u *User) UpdatePassword(ctx *ctx.Context, password, updateBy string) error
|
||||
}).Error
|
||||
}
|
||||
|
||||
func UpdateUserLastActiveTime(ctx *ctx.Context, userId int64, lastActiveTime int64) error {
|
||||
return DB(ctx).Model(&User{}).Where("id = ?", userId).Updates(map[string]interface{}{
|
||||
"last_active_time": lastActiveTime,
|
||||
"update_at": time.Now().Unix(),
|
||||
}).Error
|
||||
}
|
||||
|
||||
func (u *User) Del(ctx *ctx.Context) error {
|
||||
return DB(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("user_id=?", u.Id).Delete(&UserGroupMember{}).Error; err != nil {
|
||||
@@ -328,12 +338,18 @@ func PassLogin(ctx *ctx.Context, username, pass string) (*User, error) {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func UserTotal(ctx *ctx.Context, query string) (num int64, err error) {
|
||||
func UserTotal(ctx *ctx.Context, query string, stime, etime int64) (num int64, err error) {
|
||||
db := DB(ctx).Model(&User{})
|
||||
|
||||
if stime != 0 && etime != 0 {
|
||||
db = db.Where("last_active_time between ? and ?", stime, etime)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
num, err = Count(DB(ctx).Model(&User{}).Where("username like ? or nickname like ? or phone like ? or email like ?", q, q, q, q))
|
||||
num, err = Count(db.Where("username like ? or nickname like ? or phone like ? or email like ?", q, q, q, q))
|
||||
} else {
|
||||
num, err = Count(DB(ctx).Model(&User{}))
|
||||
num, err = Count(db)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -343,15 +359,30 @@ func UserTotal(ctx *ctx.Context, query string) (num int64, err error) {
|
||||
return num, nil
|
||||
}
|
||||
|
||||
func UserGets(ctx *ctx.Context, query string, limit, offset int) ([]User, error) {
|
||||
session := DB(ctx).Limit(limit).Offset(offset).Order("username")
|
||||
func UserGets(ctx *ctx.Context, query string, limit, offset int, stime, etime int64,
|
||||
order string, desc bool) ([]User, error) {
|
||||
|
||||
session := DB(ctx)
|
||||
|
||||
if stime != 0 && etime != 0 {
|
||||
session = session.Where("last_active_time between ? and ?", stime, etime)
|
||||
}
|
||||
|
||||
if desc {
|
||||
order = order + " desc"
|
||||
} else {
|
||||
order = order + " asc"
|
||||
}
|
||||
|
||||
session = session.Order(order)
|
||||
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("username like ? or nickname like ? or phone like ? or email like ?", q, q, q, q)
|
||||
}
|
||||
|
||||
var users []User
|
||||
err := session.Find(&users).Error
|
||||
err := session.Limit(limit).Offset(offset).Find(&users).Error
|
||||
if err != nil {
|
||||
return users, errors.WithMessage(err, "failed to query user")
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type Config struct {
|
||||
TLS bool
|
||||
StartTLS bool
|
||||
DefaultRoles []string
|
||||
DefaultTeams []int64
|
||||
RoleTeamMapping []RoleTeamMapping
|
||||
}
|
||||
|
||||
@@ -55,6 +56,7 @@ type SsoClient struct {
|
||||
TLS bool
|
||||
StartTLS bool
|
||||
DefaultRoles []string
|
||||
DefaultTeams []int64
|
||||
RoleTeamMapping map[string]RoleTeamMapping
|
||||
|
||||
Ticker *time.Ticker
|
||||
@@ -109,6 +111,7 @@ func (s *SsoClient) Reload(cf Config) {
|
||||
s.TLS = cf.TLS
|
||||
s.StartTLS = cf.StartTLS
|
||||
s.DefaultRoles = cf.DefaultRoles
|
||||
s.DefaultTeams = cf.DefaultTeams
|
||||
s.SyncAdd = cf.SyncAddUsers
|
||||
s.SyncDel = cf.SyncDelUsers
|
||||
s.SyncInterval = cf.SyncInterval
|
||||
@@ -135,8 +138,12 @@ func (s *SsoClient) Copy() *SsoClient {
|
||||
|
||||
newRoles := make([]string, len(s.DefaultRoles))
|
||||
copy(newRoles, s.DefaultRoles)
|
||||
newTeams := make([]int64, len(s.DefaultTeams))
|
||||
copy(newTeams, s.DefaultTeams)
|
||||
|
||||
lc := *s
|
||||
lc.DefaultRoles = newRoles
|
||||
lc.DefaultTeams = newTeams
|
||||
|
||||
s.RUnlock()
|
||||
|
||||
@@ -291,7 +298,7 @@ func (s *SsoClient) genLdapAttributeSearchList() []string {
|
||||
return ldapAttributes
|
||||
}
|
||||
|
||||
func LdapLogin(ctx *ctx.Context, username, pass string, defaultRoles []string, ldap *SsoClient) (*models.User, error) {
|
||||
func LdapLogin(ctx *ctx.Context, username, pass string, defaultRoles []string, defaultTeams []int64, ldap *SsoClient) (*models.User, error) {
|
||||
sr, err := ldap.LoginCheck(username, pass)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -331,6 +338,10 @@ func LdapLogin(ctx *ctx.Context, username, pass string, defaultRoles []string, l
|
||||
}
|
||||
}
|
||||
|
||||
if len(roleTeamMapping.Teams) == 0 {
|
||||
roleTeamMapping.Teams = defaultTeams
|
||||
}
|
||||
|
||||
// Synchronize group information
|
||||
if err = models.UserGroupMemberSync(ctx, roleTeamMapping.Teams, user.Id, coverTeams); err != nil {
|
||||
logger.Errorf("ldap.error: failed to update user(%s) group member err: %+v", user, err)
|
||||
@@ -347,6 +358,15 @@ func LdapLogin(ctx *ctx.Context, username, pass string, defaultRoles []string, l
|
||||
return nil, errors.WithMessage(err, "failed to add user")
|
||||
}
|
||||
|
||||
if len(roleTeamMapping.Teams) == 0 {
|
||||
for _, gid := range defaultTeams {
|
||||
err = models.UserGroupMemberAdd(ctx, gid, user.Id)
|
||||
if err != nil {
|
||||
logger.Errorf("user:%v gid:%d UserGroupMemberAdd: %s", user, gid, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = models.UserGroupMemberSync(ctx, roleTeamMapping.Teams, user.Id, false); err != nil {
|
||||
logger.Errorf("ldap.error: failed to update user(%s) group member err: %+v", user, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user