diff --git a/Dockerfile b/Dockerfile index e3423be..25a8ff3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ WORKDIR /app COPY . . -RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories RUN apk add gcc g++ RUN go env && CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -a -ldflags '-linkmode external -extldflags "-static"' -o next-terminal main.go diff --git a/main.go b/main.go index f5fffd9..acf08ba 100644 --- a/main.go +++ b/main.go @@ -132,7 +132,7 @@ func Run() error { if err := global.DB.AutoMigrate(&model.Property{}); err != nil { return err } - if err := global.DB.AutoMigrate(&model.Resource{}); err != nil { + if err := global.DB.AutoMigrate(&model.ResourceSharer{}); err != nil { return err } if err := global.DB.AutoMigrate(&model.UserGroup{}); err != nil { diff --git a/pkg/api/account.go b/pkg/api/account.go index 104a014..b499d73 100644 --- a/pkg/api/account.go +++ b/pkg/api/account.go @@ -49,7 +49,7 @@ func LoginEndpoint(c echo.Context) error { return Fail(c, -1, "您输入的账号或密码不正确") } - if user.TOTPSecret != "" { + if user.TOTPSecret != "" && user.TOTPSecret != "-" { return Fail(c, 0, "") } diff --git a/pkg/api/middleware.go b/pkg/api/middleware.go index 156a793..c1b6c41 100644 --- a/pkg/api/middleware.go +++ b/pkg/api/middleware.go @@ -1,9 +1,11 @@ package api import ( + "fmt" "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" "next-terminal/pkg/global" + "next-terminal/pkg/model" "strings" "time" ) @@ -12,6 +14,12 @@ func ErrorHandler(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { if err := next(c); err != nil { + + if he, ok := err.(*echo.HTTPError); ok { + message := fmt.Sprintf("%v", he.Message) + return Fail(c, he.Code, message) + } + return Fail(c, 0, err.Error()) } return nil @@ -21,9 +29,6 @@ func ErrorHandler(next echo.HandlerFunc) echo.HandlerFunc { func Auth(next echo.HandlerFunc) echo.HandlerFunc { urls := []string{"download", "recording", "login", "static", "favicon", "logo"} - permissionUrls := H{ - "/users": "admin", - } return func(c echo.Context) error { // 路由拦截 - 登录身份、资源权限判断等 @@ -43,14 +48,6 @@ func Auth(next echo.HandlerFunc) echo.HandlerFunc { return Fail(c, 401, "您的登录信息已失效,请重新登录后再试。") } - for url := range permissionUrls { - if strings.HasPrefix(c.Request().RequestURI, url) { - if authorization.(Authorization).User.Type != permissionUrls[url] { - return Fail(c, 403, "permission denied") - } - } - } - if authorization.(Authorization).Remember { // 记住登录有效期两周 global.Cache.Set(token, authorization, time.Hour*time.Duration(24*14)) @@ -61,3 +58,16 @@ func Auth(next echo.HandlerFunc) echo.HandlerFunc { return next(c) } } + +func Admin(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + + account, _ := GetCurrentAccount(c) + + if account.Type != model.TypeAdmin { + return Fail(c, 403, "permission denied") + } + + return next(c) + } +} diff --git a/pkg/api/resource.go b/pkg/api/resource-sharer.go similarity index 66% rename from pkg/api/resource.go rename to pkg/api/resource-sharer.go index e06415e..7cd20f9 100644 --- a/pkg/api/resource.go +++ b/pkg/api/resource-sharer.go @@ -3,7 +3,6 @@ package api import ( "github.com/labstack/echo/v4" "next-terminal/pkg/model" - "strings" ) type RU struct { @@ -12,8 +11,14 @@ type RU struct { ResourceIds []string `json:"resourceIds"` } -func ResourceGetAssignEndPoint(c echo.Context) error { - resourceId := c.Param("id") +type UR struct { + ResourceId string `json:"resourceId"` + ResourceType string `json:"resourceType"` + UserIds []string `json:"userIds"` +} + +func RSGetSharersEndPoint(c echo.Context) error { + resourceId := c.QueryParam("resourceId") userIds, err := model.FindUserIdsByResourceId(resourceId) if err != nil { return err @@ -21,13 +26,15 @@ func ResourceGetAssignEndPoint(c echo.Context) error { return Success(c, userIds) } -func ResourceOverwriteAssignEndPoint(c echo.Context) error { - resourceId := c.Param("id") - userIds := c.QueryParam("userIds") - resourceType := c.QueryParam("type") - uIds := strings.Split(userIds, ",") +func RSOverwriteSharersEndPoint(c echo.Context) error { + var ur UR + if err := c.Bind(&ur); err != nil { + return err + } - model.OverwriteUserIdsByResourceId(resourceId, resourceType, uIds) + if err := model.OverwriteUserIdsByResourceId(ur.ResourceId, ur.ResourceType, ur.UserIds); err != nil { + return err + } return Success(c, "") } diff --git a/pkg/api/routes.go b/pkg/api/routes.go index dfc8a35..5d191d4 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -44,20 +44,22 @@ func SetupRoutes() *echo.Echo { users := e.Group("/users") { - users.POST("", UserCreateEndpoint) + users.POST("", Admin(UserCreateEndpoint)) users.GET("/paging", UserPagingEndpoint) - users.PUT("/:id", UserUpdateEndpoint) - users.DELETE("/:id", UserDeleteEndpoint) - users.GET("/:id", UserGetEndpoint) + users.PUT("/:id", Admin(UserUpdateEndpoint)) + users.DELETE("/:id", Admin(UserDeleteEndpoint)) + users.GET("/:id", Admin(UserGetEndpoint)) + users.POST("/:id/change-password", Admin(UserChangePasswordEndpoint)) + users.POST("/:id/reset-totp", Admin(UserResetTotpEndpoint)) } userGroups := e.Group("/user-groups") { - userGroups.POST("", UserGroupCreateEndpoint) - userGroups.GET("/paging", UserGroupPagingEndpoint) - userGroups.PUT("/:id", UserGroupUpdateEndpoint) - userGroups.DELETE("/:id", UserGroupDeleteEndpoint) - userGroups.GET("/:id", UserGroupGetEndpoint) + userGroups.POST("", Admin(UserGroupCreateEndpoint)) + userGroups.GET("/paging", Admin(UserGroupPagingEndpoint)) + userGroups.PUT("/:id", Admin(UserGroupUpdateEndpoint)) + userGroups.DELETE("/:id", Admin(UserGroupDeleteEndpoint)) + userGroups.GET("/:id", Admin(UserGroupGetEndpoint)) //userGroups.POST("/:id/members", UserGroupAddMembersEndpoint) //userGroups.DELETE("/:id/members/:memberId", UserGroupDelMembersEndpoint) } @@ -71,7 +73,7 @@ func SetupRoutes() *echo.Echo { assets.PUT("/:id", AssetUpdateEndpoint) assets.DELETE("/:id", AssetDeleteEndpoint) assets.GET("/:id", AssetGetEndpoint) - assets.POST("/:id/change-owner", AssetChangeOwnerEndpoint) + assets.POST("/:id/change-owner", Admin(AssetChangeOwnerEndpoint)) } e.GET("/tags", AssetTagsEndpoint) @@ -83,7 +85,7 @@ func SetupRoutes() *echo.Echo { commands.PUT("/:id", CommandUpdateEndpoint) commands.DELETE("/:id", CommandDeleteEndpoint) commands.GET("/:id", CommandGetEndpoint) - commands.POST("/:id/change-owner", CommandChangeOwnerEndpoint) + commands.POST("/:id/change-owner", Admin(CommandChangeOwnerEndpoint)) } credentials := e.Group("/credentials") @@ -94,7 +96,7 @@ func SetupRoutes() *echo.Echo { credentials.PUT("/:id", CredentialUpdateEndpoint) credentials.DELETE("/:id", CredentialDeleteEndpoint) credentials.GET("/:id", CredentialGetEndpoint) - credentials.POST("/:id/change-owner", CredentialChangeOwnerEndpoint) + credentials.POST("/:id/change-owner", Admin(CredentialChangeOwnerEndpoint)) } sessions := e.Group("/sessions") @@ -102,7 +104,7 @@ func SetupRoutes() *echo.Echo { sessions.POST("", SessionCreateEndpoint) sessions.GET("/paging", SessionPagingEndpoint) sessions.POST("/:id/content", SessionContentEndpoint) - sessions.POST("/:id/discontent", SessionDiscontentEndpoint) + sessions.POST("/:id/discontent", Admin(SessionDiscontentEndpoint)) sessions.POST("/:id/resize", SessionResizeEndpoint) sessions.POST("/:id/upload", SessionUploadEndpoint) sessions.GET("/:id/download", SessionDownloadEndpoint) @@ -111,20 +113,20 @@ func SetupRoutes() *echo.Echo { sessions.DELETE("/:id/rmdir", SessionRmDirEndpoint) sessions.DELETE("/:id/rm", SessionRmEndpoint) sessions.DELETE("/:id", SessionDeleteEndpoint) - sessions.GET("/:id/recording", SessionRecordingEndpoint) + sessions.GET("/:id/recording", Admin(SessionRecordingEndpoint)) sessions.GET("/:id", SessionGetEndpoint) } - resources := e.Group("/resources") + resourceSharers := e.Group("/resource-sharers") { - resources.GET("/:id/assign", ResourceGetAssignEndPoint) - resources.POST("/:id/assign", ResourceOverwriteAssignEndPoint) - resources.POST("/remove", ResourceRemoveByUserIdAssignEndPoint) - resources.POST("/add", ResourceAddByUserIdAssignEndPoint) + resourceSharers.GET("/sharers", RSGetSharersEndPoint) + resourceSharers.POST("/overwrite-sharers", RSOverwriteSharersEndPoint) + resourceSharers.POST("/remove-resources", Admin(ResourceRemoveByUserIdAssignEndPoint)) + resourceSharers.POST("/add-resources", Admin(ResourceAddByUserIdAssignEndPoint)) } e.GET("/properties", PropertyGetEndpoint) - e.PUT("/properties", PropertyUpdateEndpoint) + e.PUT("/properties", Admin(PropertyUpdateEndpoint)) e.GET("/overview/counter", OverviewCounterEndPoint) e.GET("/overview/sessions", OverviewSessionPoint) @@ -174,15 +176,16 @@ func GetCurrentAccount(c echo.Context) (model.User, bool) { } func HasPermission(c echo.Context, owner string) bool { - // 检测是否为创建者 + // 检测是否登录 account, found := GetCurrentAccount(c) if !found { return false } + // 检测是否为管理人员 if model.TypeAdmin == account.Type { return true } - + // 检测是否为所有者 if owner == account.ID { return true } diff --git a/pkg/api/session.go b/pkg/api/session.go index 7559dc2..94383e6 100644 --- a/pkg/api/session.go +++ b/pkg/api/session.go @@ -103,6 +103,15 @@ func CloseSessionById(sessionId string, code int, reason string) { CloseSessionByWebSocket(tun.WebSocket, code, reason) } + s, err := model.FindSessionById(sessionId) + if err != nil { + return + } + + if s.Status == model.Disconnected { + return + } + global.Store.Del(sessionId) session := model.Session{} session.ID = sessionId diff --git a/pkg/api/user.go b/pkg/api/user.go index a11d8eb..b5dd86e 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -27,7 +27,6 @@ func UserCreateEndpoint(c echo.Context) error { if err := model.CreateNewUser(&item); err != nil { return err } - return Success(c, item) } @@ -89,3 +88,27 @@ func UserGetEndpoint(c echo.Context) error { return Success(c, item) } + +func UserChangePasswordEndpoint(c echo.Context) error { + id := c.Param("id") + password := c.QueryParam("password") + + passwd, err := utils.Encoder.Encode([]byte(password)) + if err != nil { + return err + } + u := &model.User{ + Password: string(passwd), + } + model.UpdateUserById(u, id) + return Success(c, "") +} + +func UserResetTotpEndpoint(c echo.Context) error { + id := c.Param("id") + u := &model.User{ + TOTPSecret: "-", + } + model.UpdateUserById(u, id) + return Success(c, "") +} diff --git a/pkg/model/asset.go b/pkg/model/asset.go index 71fc9bb..d51970a 100644 --- a/pkg/model/asset.go +++ b/pkg/model/asset.go @@ -49,11 +49,11 @@ func FindAllAsset() (o []Asset, err error) { } func FindAssetByConditions(protocol string, account User) (o []Asset, err error) { - db := global.DB.Table("assets").Select("assets.id,assets.name,assets.ip,assets.port,assets.protocol,assets.active,assets.owner,assets.created, users.nickname as owner_name,COUNT(resources.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resources on assets.id = resources.resource_id").Group("assets.id") + db := global.DB.Table("assets").Select("assets.id,assets.name,assets.ip,assets.port,assets.protocol,assets.active,assets.owner,assets.created, users.nickname as owner_name,COUNT(resource_sharers.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resource_sharers on assets.id = resource_sharers.resource_id").Group("assets.id") if TypeUser == account.Type { owner := account.ID - db = db.Where("assets.owner = ? or resources.user_id = ?", owner, owner) + db = db.Where("assets.owner = ? or resource_sharers.user_id = ?", owner, owner) } if len(protocol) > 0 { @@ -64,21 +64,21 @@ func FindAssetByConditions(protocol string, account User) (o []Asset, err error) } func FindPageAsset(pageIndex, pageSize int, name, protocol, tags string, account User, owner, sharer string) (o []AssetVo, total int64, err error) { - db := global.DB.Table("assets").Select("assets.id,assets.name,assets.ip,assets.port,assets.protocol,assets.active,assets.owner,assets.created, users.nickname as owner_name,COUNT(resources.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resources on assets.id = resources.resource_id").Group("assets.id") - dbCounter := global.DB.Table("assets").Select("DISTINCT assets.id").Joins("left join resources on assets.id = resources.resource_id") + db := global.DB.Table("assets").Select("assets.id,assets.name,assets.ip,assets.port,assets.protocol,assets.active,assets.owner,assets.created, users.nickname as owner_name,COUNT(resource_sharers.user_id) as sharer_count").Joins("left join users on assets.owner = users.id").Joins("left join resource_sharers on assets.id = resource_sharers.resource_id").Group("assets.id") + dbCounter := global.DB.Table("assets").Select("DISTINCT assets.id").Joins("left join resource_sharers on assets.id = resource_sharers.resource_id") if TypeUser == account.Type { owner := account.ID - db = db.Where("assets.owner = ? or resources.user_id = ?", owner, owner) - dbCounter = dbCounter.Where("assets.owner = ? or resources.user_id = ?", owner, owner) + db = db.Where("assets.owner = ? or resource_sharers.user_id = ?", owner, owner) + dbCounter = dbCounter.Where("assets.owner = ? or resource_sharers.user_id = ?", owner, owner) } else { if len(owner) > 0 { db = db.Where("assets.owner = ?", owner) dbCounter = dbCounter.Where("assets.owner = ?", owner) } if len(sharer) > 0 { - db = db.Where("resources.user_id = ?", sharer) - dbCounter = dbCounter.Where("resources.user_id = ?", sharer) + db = db.Where("resource_sharers.user_id = ?", sharer) + dbCounter = dbCounter.Where("resource_sharers.user_id = ?", sharer) } } diff --git a/pkg/model/command.go b/pkg/model/command.go index 23f6c4b..39fb25f 100644 --- a/pkg/model/command.go +++ b/pkg/model/command.go @@ -29,13 +29,13 @@ func (r *Command) TableName() string { func FindPageCommand(pageIndex, pageSize int, name, content string, account User) (o []CommandVo, total int64, err error) { - db := global.DB.Table("commands").Select("commands.id,commands.name,commands.content,commands.owner,commands.created, users.nickname as owner_name,COUNT(resources.user_id) as sharer_count").Joins("left join users on commands.owner = users.id").Joins("left join resources on commands.id = resources.resource_id").Group("commands.id") - dbCounter := global.DB.Table("commands").Select("DISTINCT commands.id").Joins("left join resources on commands.id = resources.resource_id") + db := global.DB.Table("commands").Select("commands.id,commands.name,commands.content,commands.owner,commands.created, users.nickname as owner_name,COUNT(resource_sharers.user_id) as sharer_count").Joins("left join users on commands.owner = users.id").Joins("left join resource_sharers on commands.id = resource_sharers.resource_id").Group("commands.id") + dbCounter := global.DB.Table("commands").Select("DISTINCT commands.id").Joins("left join resource_sharers on commands.id = resource_sharers.resource_id") if TypeUser == account.Type { owner := account.ID - db = db.Where("commands.owner = ? or resources.user_id = ?", owner, owner) - dbCounter = dbCounter.Where("commands.owner = ? or resources.user_id = ?", owner, owner) + db = db.Where("commands.owner = ? or resource_sharers.user_id = ?", owner, owner) + dbCounter = dbCounter.Where("commands.owner = ? or resource_sharers.user_id = ?", owner, owner) } if len(name) > 0 { diff --git a/pkg/model/credential.go b/pkg/model/credential.go index 66198e9..02d90b3 100644 --- a/pkg/model/credential.go +++ b/pkg/model/credential.go @@ -44,22 +44,22 @@ type CredentialSimpleVo struct { } func FindAllCredential(account User) (o []CredentialSimpleVo, err error) { - db := global.DB.Table("credentials").Select("DISTINCT credentials.id,credentials.name").Joins("left join resources on credentials.id = resources.resource_id") + db := global.DB.Table("credentials").Select("DISTINCT credentials.id,credentials.name").Joins("left join resource_sharers on credentials.id = resource_sharers.resource_id") if account.Type == TypeUser { - db = db.Where("credentials.owner = ? or resources.user_id = ?", account.ID, account.ID) + db = db.Where("credentials.owner = ? or resource_sharers.user_id = ?", account.ID, account.ID) } err = db.Find(&o).Error return } func FindPageCredential(pageIndex, pageSize int, name string, account User) (o []CredentialVo, total int64, err error) { - db := global.DB.Table("credentials").Select("credentials.id,credentials.name,credentials.type,credentials.username,credentials.owner,credentials.created,users.nickname as owner_name,COUNT(resources.user_id) as sharer_count").Joins("left join users on credentials.owner = users.id").Joins("left join resources on credentials.id = resources.resource_id").Group("credentials.id") - dbCounter := global.DB.Table("credentials").Select("DISTINCT credentials.id").Joins("left join resources on credentials.id = resources.resource_id") + db := global.DB.Table("credentials").Select("credentials.id,credentials.name,credentials.type,credentials.username,credentials.owner,credentials.created,users.nickname as owner_name,COUNT(resource_sharers.user_id) as sharer_count").Joins("left join users on credentials.owner = users.id").Joins("left join resource_sharers on credentials.id = resource_sharers.resource_id").Group("credentials.id") + dbCounter := global.DB.Table("credentials").Select("DISTINCT credentials.id").Joins("left join resource_sharers on credentials.id = resource_sharers.resource_id") if TypeUser == account.Type { owner := account.ID - db = db.Where("credentials.owner = ? or resources.user_id = ?", owner, owner) - dbCounter = dbCounter.Where("credentials.owner = ? or resources.user_id = ?", owner, owner) + db = db.Where("credentials.owner = ? or resource_sharers.user_id = ?", owner, owner) + dbCounter = dbCounter.Where("credentials.owner = ? or resource_sharers.user_id = ?", owner, owner) } if len(name) > 0 { diff --git a/pkg/model/resource-sharer.go b/pkg/model/resource-sharer.go new file mode 100644 index 0000000..096803d --- /dev/null +++ b/pkg/model/resource-sharer.go @@ -0,0 +1,128 @@ +package model + +import ( + "github.com/labstack/echo/v4" + "gorm.io/gorm" + "next-terminal/pkg/global" + "next-terminal/pkg/utils" +) + +type ResourceSharer struct { + ID string `gorm:"primary_key" json:"name"` + ResourceId string `json:"resourceId"` + ResourceType string `json:"resourceType"` + UserId string `json:"userId"` +} + +func (r *ResourceSharer) TableName() string { + return "resource_sharers" +} + +func FindUserIdsByResourceId(resourceId string) (r []string, err error) { + db := global.DB + err = db.Table("resource_sharers").Select("user_id").Where("resource_id = ?", resourceId).Find(&r).Error + if r == nil { + r = make([]string, 0) + } + return +} + +func OverwriteUserIdsByResourceId(resourceId, resourceType string, userIds []string) (err error) { + db := global.DB.Begin() + + var owner string + // 检查资产是否存在 + switch resourceType { + case "asset": + resource := Asset{} + err = db.Where("id = ?", resourceId).First(&resource).Error + owner = resource.Owner + case "command": + resource := Command{} + err = db.Where("id = ?", resourceId).First(&resource).Error + owner = resource.Owner + case "credential": + resource := Credential{} + err = db.Where("id = ?", resourceId).First(&resource).Error + owner = resource.Owner + } + + if err == gorm.ErrRecordNotFound { + return echo.NewHTTPError(404, "资源「"+resourceId+"」不存在") + } + + for i := range userIds { + if owner == userIds[i] { + return echo.NewHTTPError(400, "参数错误") + } + } + + db.Where("resource_id = ?", resourceId).Delete(&ResourceSharer{}) + + for i := range userIds { + userId := userIds[i] + if len(userId) == 0 { + continue + } + id := utils.Sign([]string{resourceId, resourceType, userId}) + resource := &ResourceSharer{ + ID: id, + ResourceId: resourceId, + ResourceType: resourceType, + UserId: userId, + } + err = db.Create(resource).Error + if err != nil { + return err + } + } + db.Commit() + return nil +} + +func DeleteByUserIdAndResourceTypeAndResourceIdIn(userId, resourceType string, resourceIds []string) error { + return global.DB.Where("user_id = ? and resource_type = ? and resource_id in ?", userId, resourceType, resourceIds).Delete(&ResourceSharer{}).Error +} + +func AddSharerResources(userId, resourceType string, resourceIds []string) error { + return global.DB.Transaction(func(tx *gorm.DB) (err error) { + + for i := range resourceIds { + resourceId := resourceIds[i] + + var owner string + // 检查资产是否存在 + switch resourceType { + case "asset": + resource := Asset{} + err = tx.Where("id = ?", resourceId).First(&resource).Error + owner = resource.Owner + case "command": + resource := Command{} + err = tx.Where("id = ?", resourceId).First(&resource).Error + owner = resource.Owner + case "credential": + resource := Credential{} + err = tx.Where("id = ?", resourceId).First(&resource).Error + owner = resource.Owner + } + + if owner == userId { + return echo.NewHTTPError(400, "参数错误") + } + + id := utils.Sign([]string{resourceId, resourceType, userId}) + resource := &ResourceSharer{ + ID: id, + ResourceId: resourceId, + ResourceType: resourceType, + UserId: userId, + } + err = tx.Create(resource).Error + if err != nil { + return err + } + } + return nil + }) +} diff --git a/pkg/model/resource.go b/pkg/model/resource.go deleted file mode 100644 index a3fa9dc..0000000 --- a/pkg/model/resource.go +++ /dev/null @@ -1,73 +0,0 @@ -package model - -import ( - "gorm.io/gorm" - "next-terminal/pkg/global" - "next-terminal/pkg/utils" -) - -type Resource struct { - ID string `gorm:"primary_key" json:"name"` - ResourceId string `json:"resourceId"` - ResourceType string `json:"resourceType"` - UserId string `json:"userId"` -} - -func (r *Resource) TableName() string { - return "resources" -} - -func FindUserIdsByResourceId(resourceId string) (r []string, err error) { - db := global.DB - err = db.Table("resources").Select("user_id").Where("resource_id = ?", resourceId).Find(&r).Error - if r == nil { - r = make([]string, 0) - } - return -} - -func OverwriteUserIdsByResourceId(resourceId, resourceType string, userIds []string) { - db := global.DB.Begin() - db.Where("resource_id = ?", resourceId).Delete(&Resource{}) - - for i := range userIds { - userId := userIds[i] - if len(userId) == 0 { - continue - } - id := utils.Sign([]string{resourceId, resourceType, userId}) - resource := &Resource{ - ID: id, - ResourceId: resourceId, - ResourceType: resourceType, - UserId: userId, - } - _ = db.Create(resource).Error - } - db.Commit() -} - -func DeleteByUserIdAndResourceTypeAndResourceIdIn(userId, resourceType string, resourceIds []string) error { - return global.DB.Where("user_id = ? and resource_type = ? and resource_id in ?", userId, resourceType, resourceIds).Delete(&Resource{}).Error -} - -func AddSharerResources(userId, resourceType string, resourceIds []string) error { - return global.DB.Transaction(func(tx *gorm.DB) (err error) { - - for i := range resourceIds { - resourceId := resourceIds[i] - id := utils.Sign([]string{resourceId, resourceType, userId}) - resource := &Resource{ - ID: id, - ResourceId: resourceId, - ResourceType: resourceType, - UserId: userId, - } - err = tx.Create(resource).Error - if err != nil { - return err - } - } - return nil - }) -} diff --git a/pkg/model/user.go b/pkg/model/user.go index 51caec7..83f5f0d 100644 --- a/pkg/model/user.go +++ b/pkg/model/user.go @@ -24,15 +24,14 @@ type User struct { } type UserVo struct { - ID string `gorm:"primary_key" json:"id"` - Username string `json:"username"` - Nickname string `json:"nickname"` - Online bool `json:"online"` - Enabled bool `json:"enabled"` - Created utils.JsonTime `json:"created"` - Type string `json:"type"` - //OwnerAssetCount int64 `json:"ownerAssetCount"` - SharerAssetCount int64 `json:"sharerAssetCount"` + ID string `gorm:"primary_key" json:"id"` + Username string `json:"username"` + Nickname string `json:"nickname"` + Online bool `json:"online"` + Enabled bool `json:"enabled"` + Created utils.JsonTime `json:"created"` + Type string `json:"type"` + SharerAssetCount int64 `json:"sharerAssetCount"` } func (r *User) TableName() string { @@ -51,7 +50,7 @@ func FindAllUser() (o []User) { } func FindPageUser(pageIndex, pageSize int, username, nickname string) (o []UserVo, total int64, err error) { - db := global.DB.Table("users").Select("users.id,users.username,users.nickname,users.online,users.enabled,users.created,users.type, count(resources.user_id) as sharer_asset_count").Joins("left join resources on users.id = resources.user_id and resources.resource_type = 'asset'").Group("users.id") + db := global.DB.Table("users").Select("users.id,users.username,users.nickname,users.online,users.enabled,users.created,users.type, count(resource_sharers.user_id) as sharer_asset_count").Joins("left join resource_sharers on users.id = resource_sharers.user_id and resource_sharers.resource_type = 'asset'").Group("users.id") dbCounter := global.DB.Table("users") if len(username) > 0 { db = db.Where("users.username like ?", "%"+username+"%") diff --git a/web/src/App.js b/web/src/App.js index 14ae9f5..625b419 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -95,10 +95,6 @@ class App extends Component { } subMenuChange = (openKeys) => { - - console.debug("current open keys"); - console.table(openKeys); - this.setState({ openKeys: openKeys }) diff --git a/web/src/components/asset/Asset.js b/web/src/components/asset/Asset.js index 113aa64..99b78fb 100644 --- a/web/src/components/asset/Asset.js +++ b/web/src/components/asset/Asset.js @@ -247,6 +247,14 @@ class Asset extends Component { tags = r2['data']; } + if (asset['tags'] && typeof (asset['tags']) === 'string') { + if (asset['tags'] === '-') { + asset['tags'] = []; + } else { + asset['tags'] = asset['tags'].split(','); + } + } + this.setState({ modalTitle: title, modalVisible: true, @@ -269,8 +277,9 @@ class Asset extends Component { modalConfirmLoading: true }); - if (formData['tagArr']) { - formData.tags = formData['tagArr'].join(','); + console.log(formData) + if (formData['tags']) { + formData.tags = formData['tags'].join(','); } if (formData.id) { @@ -368,7 +377,7 @@ class Asset extends Component { handleShowSharer = async (record) => { let r1 = this.handleSearchByNickname(''); - let r2 = request.get(`/resources/${record['id']}/assign`); + let r2 = request.get(`/resource-sharers/sharers?resourceId=${record['id']}`); await r1; let result = await r2; @@ -380,10 +389,20 @@ class Asset extends Component { selectedSharers = result['data']; } + let users = this.state.users; + users = users.map(item => { + let disabled = false; + if (record['owner'] === item['id']) { + disabled = true; + } + return {...item, 'disabled': disabled} + }); + this.setState({ selectedSharers: selectedSharers, selected: record, - changeSharerModalVisible: true + changeSharerModalVisible: true, + users: users }) } @@ -687,9 +706,8 @@ class Asset extends Component { : null } - - 更换资源「{this.state.selected['name']}」的所有者 - } + 更换资源「{this.state.selected['name']}」的所有者 + } visible={this.state.changeOwnerModalVisible} confirmLoading={this.state.changeOwnerConfirmLoading} onOk={() => { @@ -746,54 +764,64 @@ class Asset extends Component { - 更新资源「{this.state.selected['name']}」的授权人 - } - visible={this.state.changeSharerModalVisible} - confirmLoading={this.state.changeSharerConfirmLoading} - onOk={async () => { - this.setState({ - changeSharerConfirmLoading: true - }); - let changeSharerModalVisible = false; + { + this.state.changeSharerModalVisible ? + 更新资源「{this.state.selected['name']}」的授权人 + } + visible={this.state.changeSharerModalVisible} + confirmLoading={this.state.changeSharerConfirmLoading} + onOk={async () => { + this.setState({ + changeSharerConfirmLoading: true + }); - let result = await request.post(`/resources/${this.state.selected['id']}/assign?type=asset&userIds=${this.state.selectedSharers.join(',')}`); - if (result['code'] === 1) { - message.success('操作成功'); - this.loadTableData(); - } else { - message.error(result['message'], 10); - changeSharerModalVisible = true; - } + let changeSharerModalVisible = false; - this.setState({ - changeSharerConfirmLoading: false, - changeSharerModalVisible: changeSharerModalVisible - }) - }} - onCancel={() => { - this.setState({ - changeSharerModalVisible: false - }) - }} - okButtonProps={{disabled: !hasPermission(this.state.selected['owner'])}} - > + let result = await request.post(`/resource-sharers/overwrite-sharers`, { + resourceId: this.state.selected['id'], + resourceType: 'asset', + userIds: this.state.selectedSharers + }); + if (result['code'] === 1) { + message.success('操作成功'); + this.loadTableData(); + } else { + message.error(result['message'], 10); + changeSharerModalVisible = true; + } + + this.setState({ + changeSharerConfirmLoading: false, + changeSharerModalVisible: changeSharerModalVisible + }) + }} + onCancel={() => { + this.setState({ + changeSharerModalVisible: false + }) + }} + okButtonProps={{disabled: !hasPermission(this.state.selected['owner'])}} + > + + `${item.nickname}`} + /> + : undefined + } - `${item.nickname}`} - /> - ); diff --git a/web/src/components/asset/AssetModal.js b/web/src/components/asset/AssetModal.js index 0e60b67..cc7427a 100644 --- a/web/src/components/asset/AssetModal.js +++ b/web/src/components/asset/AssetModal.js @@ -39,13 +39,6 @@ const AssetModal = function ({title, visible, handleOk, handleCancel, confirmLoa } } - let initAssetTags = []; - if (!isEmpty(model['tags'])) { - initAssetTags = model['tags'].split(','); - } - - let [assetTags, setAssetTags] = useState(initAssetTags); - const formItemLayout = { labelCol: {span: 6}, wrapperCol: {span: 14}, @@ -100,10 +93,6 @@ const AssetModal = function ({title, visible, handleOk, handleCancel, confirmLoa model.accountType = v; } - const handleTagsChange = v => { - setAssetTags(v); - } - return ( - {tags.map(tag => { if (tag === '-') { return undefined; diff --git a/web/src/components/command/DynamicCommand.js b/web/src/components/command/DynamicCommand.js index 2962847..b40e095 100644 --- a/web/src/components/command/DynamicCommand.js +++ b/web/src/components/command/DynamicCommand.js @@ -311,7 +311,7 @@ class DynamicCommand extends Component { handleShowSharer = async (record) => { let r1 = this.handleSearchByNickname(''); - let r2 = request.get(`/resources/${record['id']}/assign`); + let r2 = request.get(`/resource-sharers/sharers?resourceId=${record['id']}`); await r1; let result = await r2; @@ -323,10 +323,20 @@ class DynamicCommand extends Component { selectedSharers = result['data']; } + let users = this.state.users; + users = users.map(item => { + let disabled = false; + if (record['owner'] === item['id']) { + disabled = true; + } + return {...item, 'disabled': disabled} + }); + this.setState({ selectedSharers: selectedSharers, selected: record, - changeSharerModalVisible: true + changeSharerModalVisible: true, + users: users }) } @@ -657,8 +667,8 @@ class DynamicCommand extends Component { - 更换资源「{this.state.selected['name']}」的所有者 - } + 更换资源「{this.state.selected['name']}」的所有者 + } visible={this.state.changeOwnerModalVisible} confirmLoading={this.state.changeOwnerConfirmLoading} onOk={() => { @@ -715,54 +725,63 @@ class DynamicCommand extends Component { - 更新资源「{this.state.selected['name']}」的授权人 - } - visible={this.state.changeSharerModalVisible} - confirmLoading={this.state.changeSharerConfirmLoading} - onOk={async () => { - this.setState({ - changeSharerConfirmLoading: true - }); + { + this.state.changeSharerModalVisible ? + 更新资源「{this.state.selected['name']}」的授权人 + } + visible={this.state.changeSharerModalVisible} + confirmLoading={this.state.changeSharerConfirmLoading} + onOk={async () => { + this.setState({ + changeSharerConfirmLoading: true + }); - let changeSharerModalVisible = false; + let changeSharerModalVisible = false; - let result = await request.post(`/resources/${this.state.selected['id']}/assign?type=command&userIds=${this.state.selectedSharers.join(',')}`); - if (result['code'] === 1) { - message.success('操作成功'); - this.loadTableData(); - } else { - message.error(result['message'], 10); - changeSharerModalVisible = true; - } + let result = await request.post(`/resource-sharers/overwrite-sharers`, { + resourceId: this.state.selected['id'], + resourceType: 'command', + userIds: this.state.selectedSharers + }); + if (result['code'] === 1) { + message.success('操作成功'); + this.loadTableData(); + } else { + message.error(result['message'], 10); + changeSharerModalVisible = true; + } - this.setState({ - changeSharerConfirmLoading: false, - changeSharerModalVisible: changeSharerModalVisible - }) - }} - onCancel={() => { - this.setState({ - changeSharerModalVisible: false - }) - }} - okButtonProps={{disabled: !hasPermission(this.state.selected['owner'])}} - > + this.setState({ + changeSharerConfirmLoading: false, + changeSharerModalVisible: changeSharerModalVisible + }) + }} + onCancel={() => { + this.setState({ + changeSharerModalVisible: false + }) + }} + okButtonProps={{disabled: !hasPermission(this.state.selected['owner'])}} + > + + `${item.nickname}`} + /> + : undefined + } - `${item.nickname}`} - /> - diff --git a/web/src/components/command/DynamicCommandModal.js b/web/src/components/command/DynamicCommandModal.js index 914f671..20aea46 100644 --- a/web/src/components/command/DynamicCommandModal.js +++ b/web/src/components/command/DynamicCommandModal.js @@ -44,11 +44,11 @@ const DynamicCommandModal = ({title, visible, handleOk, handleCancel, confirmLoa - + -