diff --git a/models/models.go b/models/models.go index 8a2ce07a2..341dbe5a4 100755 --- a/models/models.go +++ b/models/models.go @@ -169,6 +169,7 @@ func init() { new(BadgeUserLog), new(TechConvergeBaseInfo), new(RepoConvergeInfo), + new(UserRole), ) tablesStatistic = append(tablesStatistic, diff --git a/models/role.go b/models/role.go new file mode 100644 index 000000000..9f2686c51 --- /dev/null +++ b/models/role.go @@ -0,0 +1,68 @@ +package models + +import ( + "code.gitea.io/gitea/modules/timeutil" + "fmt" +) + +type RoleType string + +const ( + TechProgramAdmin RoleType = "TechProgramAdmin" +) + +type Role struct { + Type RoleType + Name string + Description string +} + +type UserRole struct { + ID int64 `xorm:"pk autoincr"` + RoleType RoleType + UserId int64 `xorm:"INDEX"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` +} + +func NewUserRole(r UserRole) (int64, error) { + return x.Insert(&r) +} + +func GetUserRoleByUserAndRole(userId int64, roleType RoleType) (*UserRole, error) { + r := &UserRole{} + has, err := x.Where("role_type = ? and user_id = ?", roleType, userId).Get(r) + if err != nil { + return nil, err + } else if !has { + return nil, ErrRecordNotExist{} + } + return r, nil +} + +func GetRoleByCode(code string) (*Role, error) { + r := &Role{} + has, err := x.Where("code = ?", code).Get(r) + if err != nil { + return nil, err + } else if !has { + return nil, ErrRecordNotExist{} + } + return r, nil +} + +type ErrRoleNotExists struct { +} + +func IsErrRoleNotExists(err error) bool { + _, ok := err.(ErrRoleNotExists) + return ok +} + +func (err ErrRoleNotExists) Error() string { + return fmt.Sprintf("role is not exists") +} + +type AddRoleReq struct { + UserName string `json:"user_name" binding:"Required"` + RoleType RoleType `json:"role_type" binding:"Required"` +} diff --git a/routers/api/v1/admin/role.go b/routers/api/v1/admin/role.go new file mode 100644 index 000000000..c016ef284 --- /dev/null +++ b/routers/api/v1/admin/role.go @@ -0,0 +1,23 @@ +package admin + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/routers/response" + "code.gitea.io/gitea/services/role" + "net/http" +) + +func AddRole(ctx *context.APIContext, form models.AddRoleReq) { + user, err := models.GetUserByName(form.UserName) + if err != nil { + ctx.JSON(http.StatusOK, response.ServerError("User not exists")) + return + } + err = role.AddUserRole(user.ID, form.RoleType) + if err != nil { + ctx.JSON(http.StatusOK, response.ResponseError(err)) + return + } + ctx.JSON(http.StatusOK, response.Success()) +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 303c345a2..0eac9b02c 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -59,6 +59,7 @@ package v1 import ( + "code.gitea.io/gitea/services/role" "net/http" "strings" @@ -214,6 +215,16 @@ func reqSiteAdmin() macaron.Handler { } } +// reqTechAdmin user should be the tech program admin +func hasRole(roleType models.RoleType) macaron.Handler { + return func(ctx *context.Context) { + if !ctx.IsSigned || !role.UserHasRole(ctx.User.ID, roleType) { + ctx.Error(http.StatusForbidden) + return + } + } +} + // reqOwner user should be the owner of the repo or site admin. func reqOwner() macaron.Handler { return func(ctx *context.Context) { @@ -545,7 +556,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/repo_search", tech.SearchRepoInfo) m.Post("/openi", bind(api.OpenITechRepo{}), tech.CommitOpenIRepo) m.Post("/no_openi", bind(api.NotOpenITechRepo{}), tech.CommitNotOpenIRepo) - + m.Get("/is_admin", tech.IsAdmin) }, reqToken()) m.Group("/attachments", func() { @@ -1178,6 +1189,9 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo) }) }) + m.Group("/role", func() { + m.Post("", bind(models.AddRoleReq{}), admin.AddRole) + }) }, reqToken(), reqSiteAdmin()) m.Group("/topics", func() { diff --git a/routers/api/v1/tech/tech.go b/routers/api/v1/tech/tech.go index d19056ce0..3fcbdd669 100644 --- a/routers/api/v1/tech/tech.go +++ b/routers/api/v1/tech/tech.go @@ -2,6 +2,7 @@ package tech import ( "code.gitea.io/gitea/routers/response" + "code.gitea.io/gitea/services/role" techService "code.gitea.io/gitea/services/tech" "net/http" "strconv" @@ -251,3 +252,16 @@ func FindTech(ctx *context.APIContext) { } ctx.JSON(http.StatusOK, response.OuterSuccessWithData(r)) } + +func IsAdmin(ctx *context.APIContext) { + userName := ctx.Query("user") + user, err := models.GetUserByName(userName) + if err != nil { + ctx.JSON(http.StatusOK, response.ServerError("User not exists")) + return + } + isAdmin := role.UserHasRole(user.ID, models.TechProgramAdmin) + r := map[string]interface{}{} + r["is_admin"] = isAdmin + ctx.JSON(http.StatusOK, response.OuterSuccessWithData(r)) +} diff --git a/services/role/role.go b/services/role/role.go new file mode 100644 index 000000000..ccc78f2e5 --- /dev/null +++ b/services/role/role.go @@ -0,0 +1,15 @@ +package role + +import "code.gitea.io/gitea/models" + +var roleMap = map[models.RoleType]*models.Role{ + models.TechProgramAdmin: { + Type: models.TechProgramAdmin, + Name: "科技项目管理员", + Description: "拥有科技项目管理相关功能的管理员权限", + }, +} + +func GetRole(roleType models.RoleType) *models.Role { + return roleMap[roleType] +} diff --git a/services/role/user_role.go b/services/role/user_role.go new file mode 100644 index 000000000..5db6bbca0 --- /dev/null +++ b/services/role/user_role.go @@ -0,0 +1,26 @@ +package role + +import ( + "code.gitea.io/gitea/models" +) + +func AddUserRole(userId int64, roleType models.RoleType) error { + role := GetRole(roleType) + if role == nil { + return models.ErrRoleNotExists{} + } + _, err := models.NewUserRole(models.UserRole{UserId: userId, RoleType: roleType}) + return err +} + +func UserHasRole(userId int64, roleType models.RoleType) bool { + role := GetRole(roleType) + if role == nil { + return false + } + _, err := models.GetUserRoleByUserAndRole(userId, roleType) + if err != nil { + return false + } + return true +}