db refactor

This commit is contained in:
Wenkai Yin 2016-03-28 15:34:41 +08:00
parent a61cf3625a
commit ac5bbc4657
12 changed files with 415 additions and 242 deletions

View File

@ -16,6 +16,7 @@
package api package api
import ( import (
"fmt"
"net/http" "net/http"
"strconv" "strconv"
@ -23,6 +24,7 @@ import (
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/vmware/harbor/utils/log"
) )
// ProjectMemberAPI handles request to /api/projects/{}/members/{} // ProjectMemberAPI handles request to /api/projects/{}/members/{}
@ -148,7 +150,13 @@ func (pma *ProjectMemberAPI) Post() {
} }
for _, rid := range req.Roles { for _, rid := range req.Roles {
err = dao.AddUserProjectRole(userID, pid, int(rid)) role, err := dao.IntToRole(rid)
if err != nil {
log.Error(err)
pma.RenderError(http.StatusBadRequest, fmt.Sprintf("Invalid role: %d", rid))
}
err = dao.AddProjectMember(pid, userID, role)
if err != nil { if err != nil {
beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", userID, ", role id:", rid) beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", userID, ", role id:", rid)
pma.RenderError(http.StatusInternalServerError, "Failed to update data in database") pma.RenderError(http.StatusInternalServerError, "Failed to update data in database")
@ -182,7 +190,7 @@ func (pma *ProjectMemberAPI) Put() {
} }
//TODO: delete and insert should in one transaction //TODO: delete and insert should in one transaction
//delete user project role record for the given user //delete user project role record for the given user
err = dao.DeleteUserProjectRoles(mid, pid) err = dao.DeleteProjectMember(pid, mid)
if err != nil { if err != nil {
beego.Error("Failed to delete project roles for user, user id:", mid, ", project id: ", pid, ", error: ", err) beego.Error("Failed to delete project roles for user, user id:", mid, ", project id: ", pid, ", error: ", err)
pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB") pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB")
@ -190,7 +198,13 @@ func (pma *ProjectMemberAPI) Put() {
} }
//insert roles in request //insert roles in request
for _, rid := range req.Roles { for _, rid := range req.Roles {
err = dao.AddUserProjectRole(mid, pid, int(rid)) role, err := dao.IntToRole(rid)
if err != nil {
log.Error(err)
pma.RenderError(http.StatusBadRequest, fmt.Sprintf("Invalid role: %d", rid))
}
err = dao.AddProjectMember(pid, mid, role)
if err != nil { if err != nil {
beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", mid, ", role id:", rid) beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", mid, ", role id:", rid)
pma.RenderError(http.StatusInternalServerError, "Failed to update data in database") pma.RenderError(http.StatusInternalServerError, "Failed to update data in database")
@ -210,7 +224,7 @@ func (pma *ProjectMemberAPI) Delete() {
pma.RenderError(http.StatusForbidden, "") pma.RenderError(http.StatusForbidden, "")
return return
} }
err = dao.DeleteUserProjectRoles(mid, pid) err = dao.DeleteProjectMember(pid, mid)
if err != nil { if err != nil {
beego.Error("Failed to delete project roles for user, user id:", mid, ", project id:", pid, ", error:", err) beego.Error("Failed to delete project roles for user, user id:", mid, ", project id:", pid, ", error:", err)
pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB") pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB")

View File

@ -17,11 +17,12 @@ package dao
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"testing" "testing"
"time" "time"
"github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
"github.com/astaxie/beego/orm" "github.com/astaxie/beego/orm"
@ -41,44 +42,61 @@ func execUpdate(o orm.Ormer, sql string, params interface{}) error {
} }
func clearUp(username string) { func clearUp(username string) {
var err error
o := orm.NewOrm() o := orm.NewOrm()
o.Begin() o.Begin()
err := execUpdate(o, `delete upr from user_project_role upr
left join project_role pr on upr.pr_id = pr.pr_id err = execUpdate(o, `delete pm
left join project p on pr.project_id = p.project_id from project_member pm
left join user u on u.user_id = p.owner_id join user u
on pm.user_id = u.user_id
where u.username = ?`, username) where u.username = ?`, username)
if err != nil { if err != nil {
o.Rollback() o.Rollback()
log.Println(err) log.Error(err)
} }
err = execUpdate(o, `delete pr from project_role pr
left join project p on pr.project_id = p.project_id err = execUpdate(o, `delete pm
left join user u on u.user_id = p.owner_id from project_member pm
where u.username = ?`, username) join project p
on pm.project_id = p.project_id
where p.name = ?`, projectName)
if err != nil { if err != nil {
o.Rollback() o.Rollback()
log.Println(err) log.Error(err)
} }
err = execUpdate(o, `delete a from access_log a
left join user u on a.user_id = u.user_id err = execUpdate(o, `delete al
from access_log al
join user u
on al.user_id = u.user_id
where u.username = ?`, username) where u.username = ?`, username)
if err != nil { if err != nil {
o.Rollback() o.Rollback()
log.Println(err) log.Error(err)
} }
err = execUpdate(o, `delete p from project p
left join user u on p.owner_id = u.user_id err = execUpdate(o, `delete al
where u.username = ?`, username) from access_log al
join project p
on al.project_id = p.project_id
where p.name = ?`, projectName)
if err != nil { if err != nil {
o.Rollback() o.Rollback()
log.Println(err) log.Error(err)
} }
err = execUpdate(o, `delete u from user u
where u.username = ?`, username) err = execUpdate(o, `delete from project where name = ?`, projectName)
if err != nil { if err != nil {
o.Rollback() o.Rollback()
log.Println(err) log.Error(err)
}
err = execUpdate(o, `delete from user where username = ?`, username)
if err != nil {
o.Rollback()
log.Error(err)
} }
o.Commit() o.Commit()
} }
@ -379,32 +397,6 @@ func TestGetProject(t *testing.T) {
} }
} }
func getProjectRole(projectID int64) []models.Role {
o := orm.NewOrm()
var r []models.Role
_, err := o.Raw(`select r.role_id, r.name
from project_role pr
left join role r on pr.role_id = r.role_id
where project_id = ?`, projectID).QueryRows(&r)
if err != nil {
log.Printf("Error occurred in querying project_role: %v", err)
}
return r
}
func TestCheckProjectRoles(t *testing.T) {
r := getProjectRole(currentProject.ProjectID)
if len(r) != 3 {
t.Errorf("The length of project roles is not 3")
}
if r[1].RoleID != 3 {
t.Errorf("The role id does not match, expected: 3, acutal: %d", r[1].RoleID)
}
if r[1].Name != "developer" {
t.Errorf("The name of role id: 3 should be developer, actual:%s", r[1].Name)
}
}
func TestGetAccessLog(t *testing.T) { func TestGetAccessLog(t *testing.T) {
queryAccessLog := models.AccessLog{ queryAccessLog := models.AccessLog{
UserID: currentUser.UserID, UserID: currentUser.UserID,
@ -546,20 +538,6 @@ func TestQueryProject(t *testing.T) {
} }
} }
func getUserProjectRole(projectID int64, userID int) []models.Role {
o := orm.NewOrm()
var r []models.Role
_, err := o.Raw(`select r.role_id, r.name
from user_project_role upr
left join project_role pr on upr.pr_id = pr.pr_id
left join role r on r.role_id = pr.role_id
where pr.project_id = ? and upr.user_id = ?`, projectID, userID).QueryRows(&r)
if err != nil {
log.Fatalf("Error occurred in querying user_project_role: %v", err)
}
return r
}
func TestGetUserProjectRoles(t *testing.T) { func TestGetUserProjectRoles(t *testing.T) {
user := *currentUser user := *currentUser
r, err := GetUserProjectRoles(user, currentProject.ProjectID) r, err := GetUserProjectRoles(user, currentProject.ProjectID)
@ -575,16 +553,6 @@ func TestGetUserProjectRoles(t *testing.T) {
if r[0].Name != "projectAdmin" { if r[0].Name != "projectAdmin" {
t.Errorf("the expected rolename is: projectAdmin, actual: %s", r[0].Name) t.Errorf("the expected rolename is: projectAdmin, actual: %s", r[0].Name)
} }
user.RoleID = 1
r, err = GetUserProjectRoles(user, currentProject.ProjectID)
if err != nil {
t.Errorf("Error happened in GetUserProjectRole: %v, user: %+v, project Id: %d", err, user, currentProject.ProjectID)
}
//Get the size of current user project role.
if len(r) != 0 {
t.Errorf("The user, id: %d, should not have role id: 1 in project id: %d, actual role list: %v", currentUser.UserID, currentProject.ProjectID, r)
}
} }
func TestProjectPermission(t *testing.T) { func TestProjectPermission(t *testing.T) {
@ -610,34 +578,43 @@ func TestQueryRelevantProjects(t *testing.T) {
} }
} }
func TestAssignUserProjectRole(t *testing.T) { func TestAddProjectMember(t *testing.T) {
err := AddUserProjectRole(currentUser.UserID, currentProject.ProjectID, developer) err := AddProjectMember(currentProject.ProjectID, 1, Developer)
if err != nil { if err != nil {
t.Errorf("Error occurred in AddUserProjectRole: %v", err) t.Errorf("Error occurred in AddProjectMember: %v", err)
} }
r := getUserProjectRole(currentProject.ProjectID, currentUser.UserID) roles, err := GetUserProjectRoles(models.User{UserID: 1}, currentProject.ProjectID)
if err != nil {
//Get the size of current user project role info. t.Errorf("Error occurred in GetUserProjectRoles: %v", err)
if len(r) != 2 {
t.Errorf("Expected length of role list is 2, actual: %d", len(r))
} }
if r[1].RoleID != 3 { flag := false
t.Errorf("Expected role id of the second role in list is 3, actual: %d", r[1].RoleID) for _, role := range roles {
if role.Name == "developer" {
flag = true
break
}
}
if !flag {
t.Errorf("the user which ID is 1 does not have developer privileges")
} }
} }
func TestDeleteUserProjectRole(t *testing.T) { func TestDeleteProjectMember(t *testing.T) {
err := DeleteUserProjectRoles(currentUser.UserID, currentProject.ProjectID) err := DeleteProjectMember(currentProject.ProjectID, 1)
if err != nil { if err != nil {
t.Errorf("Error occurred in DeleteUserProjectRoles: %v", err) t.Errorf("Error occurred in DeleteProjectMember: %v", err)
} }
r := getUserProjectRole(currentProject.ProjectID, currentUser.UserID) roles, err := GetUserProjectRoles(models.User{UserID: 1}, currentProject.ProjectID)
//Get the size of current user project role. if err != nil {
if len(r) != 0 { t.Errorf("Error occurred in GetUserProjectRoles: %v", err)
t.Errorf("Expected role list length is 0, actual: %d, role list: %+v", len(r), r) }
if len(roles) != 0 {
t.Errorf("delete record failed from table project_member")
} }
} }

View File

@ -15,12 +15,14 @@
package dao package dao
/*
import ( import (
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
"github.com/astaxie/beego/orm" "github.com/astaxie/beego/orm"
) )
// GetUserByProject gets all members of the project. // GetUserByProject gets all members of the project.
func GetUserByProject(projectID int64, queryUser models.User) ([]models.User, error) { func GetUserByProject(projectID int64, queryUser models.User) ([]models.User, error) {
o := orm.NewOrm() o := orm.NewOrm()
@ -47,3 +49,4 @@ func GetUserByProject(projectID int64, queryUser models.User) ([]models.User, er
_, err := o.Raw(sql, queryParam).QueryRows(&u) _, err := o.Raw(sql, queryParam).QueryRows(&u)
return u, err return u, err
} }
*/

View File

@ -40,12 +40,13 @@ func AddProject(project models.Project) error {
o := orm.NewOrm() o := orm.NewOrm()
p, err := o.Raw("insert into project (owner_id, name, creation_time, deleted, public) values (?, ?, now(), ?, ?)").Prepare() p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare()
if err != nil { if err != nil {
return err return err
} }
r, err := p.Exec(project.OwnerID, project.Name, project.Deleted, project.Public) now := time.Now()
r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted, project.Public)
if err != nil { if err != nil {
return err return err
} }
@ -55,27 +56,7 @@ func AddProject(project models.Project) error {
return err return err
} }
projectAdminRole := models.ProjectRole{ProjectID: projectID, RoleID: models.PROJECTADMIN} if err = AddProjectMember(projectID, project.OwnerID, ProjectAdmin); err != nil {
_, err = AddProjectRole(projectAdminRole)
if err != nil {
return err
}
projectDeveloperRole := models.ProjectRole{ProjectID: projectID, RoleID: models.DEVELOPER}
_, err = AddProjectRole(projectDeveloperRole)
if err != nil {
return err
}
projectGuestRole := models.ProjectRole{ProjectID: projectID, RoleID: models.GUEST}
_, err = AddProjectRole(projectGuestRole)
if err != nil {
return err
}
//Add all project roles, after that when assigning a user to a project just update the upr table
err = AddUserProjectRole(project.OwnerID, projectID, models.PROJECTADMIN)
if err != nil {
return err return err
} }
@ -103,11 +84,9 @@ func QueryProject(query models.Project) ([]models.Project, error) {
o := orm.NewOrm() o := orm.NewOrm()
sql := `select distinct sql := `select distinct
p.project_id, p.owner_id, p.name,p.creation_time, p.public p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public
from project p from project p
left join project_role pr on p.project_id = pr.project_id left join project_member pm on p.project_id = pm.project_id
left join user_project_role upr on upr.pr_id = pr.pr_id
left join user u on u.user_id = upr.user_id
where p.deleted = 0 ` where p.deleted = 0 `
queryParam := make([]interface{}, 1) queryParam := make([]interface{}, 1)
@ -116,8 +95,7 @@ func QueryProject(query models.Project) ([]models.Project, error) {
sql += ` and p.public = ?` sql += ` and p.public = ?`
queryParam = append(queryParam, query.Public) queryParam = append(queryParam, query.Public)
} else if isAdmin, _ := IsAdminRole(query.UserID); isAdmin == false { } else if isAdmin, _ := IsAdminRole(query.UserID); isAdmin == false {
sql += ` and (p.owner_id = ? or u.user_id = ?) ` sql += ` and (pm.user_id = ?) `
queryParam = append(queryParam, query.UserID)
queryParam = append(queryParam, query.UserID) queryParam = append(queryParam, query.UserID)
} }
@ -161,60 +139,65 @@ func ProjectExists(nameOrID interface{}) (bool, error) {
} }
// GetProjectByID ... // GetProjectByID ...
func GetProjectByID(projectID int64) (*models.Project, error) { func GetProjectByID(id int64) (*models.Project, error) {
o := orm.NewOrm() o := orm.NewOrm()
sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.public sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time, p.public
from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?` from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
queryParam := make([]interface{}, 1) queryParam := make([]interface{}, 1)
queryParam = append(queryParam, projectID) queryParam = append(queryParam, id)
p := []models.Project{} p := []models.Project{}
count, err := o.Raw(sql, queryParam).QueryRows(&p) count, err := o.Raw(sql, queryParam).QueryRows(&p)
if err != nil { if err != nil {
return nil, err return nil, err
} else if count == 0 {
return nil, nil
} else {
return &p[0], nil
} }
if count == 0 {
return nil, nil
}
return &p[0], nil
} }
// GetProjectByName ... // GetProjectByName ...
func GetProjectByName(projectName string) (*models.Project, error) { func GetProjectByName(name string) (*models.Project, error) {
o := orm.NewOrm() o := orm.NewOrm()
var p []models.Project var p []models.Project
n, err := o.Raw(`select project_id, owner_id, name, deleted, public from project where name = ? and deleted = 0`, projectName).QueryRows(&p) n, err := o.Raw(`select * from project where name = ? and deleted = 0`, name).QueryRows(&p)
if err != nil { if err != nil {
return nil, err return nil, err
} else if n == 0 {
return nil, nil
} else {
return &p[0], nil
} }
if n == 0 {
return nil, nil
}
return &p[0], nil
} }
// GetPermission gets roles that the user has according to the project. // GetPermission gets roles that the user has according to the project.
func GetPermission(username, projectName string) (string, error) { func GetPermission(username, projectName string) (string, error) {
o := orm.NewOrm() o := orm.NewOrm()
sql := "select r.role_code from role as r " + sql := `select r.role_code from role as r
"inner join project_role as pr on r.role_id = pr.role_id " + inner join project_member as pm on r.role_id = pm.role
"inner join user_project_role as ur on pr.pr_id = ur.pr_id " + inner join user as u on u.user_id = pm.user_id
"inner join user as u on u.user_id = ur.user_id " + inner join project p on p.project_id = pm.project_id
"inner join project p on p.project_id = pr.project_id " + where u.username = ? and p.name = ? and u.deleted = 0 and p.deleted = 0`
"where u.username = ? and p.name = ? and u.deleted = 0 and p.deleted = 0"
var r []models.Role var r []models.Role
n, err := o.Raw(sql, username, projectName).QueryRows(&r) n, err := o.Raw(sql, username, projectName).QueryRows(&r)
if err != nil { if err != nil {
return "", err return "", err
} else if n == 0 {
return "", nil
} else {
return r[0].RoleCode, nil
} }
if n == 0 {
return "", nil
}
return r[0].RoleCode, nil
} }
// ToggleProjectPublicity toggles the publicity of the project. // ToggleProjectPublicity toggles the publicity of the project.
@ -228,10 +211,11 @@ func ToggleProjectPublicity(projectID int64, publicity int) error {
// QueryRelevantProjects returns all projects that the user is a member of. // QueryRelevantProjects returns all projects that the user is a member of.
func QueryRelevantProjects(userID int) ([]models.Project, error) { func QueryRelevantProjects(userID int) ([]models.Project, error) {
o := orm.NewOrm() o := orm.NewOrm()
sql := `SELECT distinct p.project_id, p.name, p.public FROM registry.project p sql := `select distinct p.project_id, p.name, p.public
left join project_role pr on p.project_id = pr.project_id from project p
left join user_project_role upr on upr.pr_id = pr.pr_id left join project_member pm on p.project_id = pm.project_id
where upr.user_id = ? or p.public = 1 and p.deleted = 0` left join user u on u.user_id = pm.user_id
where u.user_id = ? or p.public = 1 and p.deleted = 0`
var res []models.Project var res []models.Project
_, err := o.Raw(sql, userID).QueryRows(&res) _, err := o.Raw(sql, userID).QueryRows(&res)
if err != nil { if err != nil {

94
dao/projectmember.go Normal file
View File

@ -0,0 +1,94 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dao
import (
"github.com/astaxie/beego/orm"
"github.com/vmware/harbor/models"
)
// AddProjectMember inserts a record to table project_member
func AddProjectMember(projectID int64, userID int, r role) error {
o := orm.NewOrm()
sql := "insert into project_member (project_id, user_id , role) values (?, ?, ?)"
rr, err := getRole(r)
if err != nil {
return err
}
if _, err = o.Raw(sql, projectID, userID, rr.RoleID).Exec(); err != nil {
return err
}
return nil
}
// UpdateProjectMember updates the record in table project_member
func UpdateProjectMember(projectID int64, userID int, r role) error {
o := orm.NewOrm()
sql := "update project_member set role = ? where project_id = ? and user_id = ?"
rr, err := getRole(r)
if err != nil {
return err
}
if _, err := o.Raw(sql, rr.RoleID, projectID, userID).Exec(); err != nil {
return err
}
return nil
}
// DeleteProjectMember delete the record from table project_member
func DeleteProjectMember(projectID int64, userID int) error {
o := orm.NewOrm()
sql := "delete from project_member where project_id = ? and user_id = ?"
if _, err := o.Raw(sql, projectID, userID).Exec(); err != nil {
return err
}
return nil
}
// GetUserByProject gets all members of the project.
func GetUserByProject(projectID int64, queryUser models.User) ([]models.User, error) {
o := orm.NewOrm()
u := []models.User{}
sql := `select u.user_id, u.username, r.name rolename, r.role_id
from user u
join project_member pm
on pm.project_id = ? and u.user_id = pm.user_id
join role r
on pm.role = r.role_id
where u.deleted = 0`
queryParam := make([]interface{}, 1)
queryParam = append(queryParam, projectID)
if queryUser.Username != "" {
sql += " and u.username like ? "
queryParam = append(queryParam, queryUser.Username)
}
sql += ` order by u.user_id `
_, err := o.Raw(sql, queryParam).QueryRows(&u)
return u, err
}

View File

@ -15,6 +15,7 @@
package dao package dao
/*
import ( import (
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
@ -37,6 +38,7 @@ func AddProjectRole(projectRole models.ProjectRole) (int64, error) {
return id, err return id, err
} }
// AddUserProjectRole inserts role information to table project_role and user_project_role. // AddUserProjectRole inserts role information to table project_role and user_project_role.
func AddUserProjectRole(userID int, projectID int64, roleID int) error { func AddUserProjectRole(userID int, projectID int64, roleID int) error {
@ -91,3 +93,6 @@ func DeleteUserProjectRoles(userID int, projectID int64) error {
_, err = p.Exec(userID, projectID) _, err = p.Exec(userID, projectID)
return err return err
} }
*/

View File

@ -18,6 +18,7 @@ package dao
import ( import (
"errors" "errors"
"regexp" "regexp"
"time"
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
"github.com/vmware/harbor/utils" "github.com/vmware/harbor/utils"
@ -34,7 +35,8 @@ func Register(user models.User) (int64, error) {
} }
o := orm.NewOrm() o := orm.NewOrm()
p, err := o.Raw("insert into user (username, password, realname, email, comment, salt) values (?, ?, ?, ?, ?, ?)").Prepare()
p, err := o.Raw("insert into user (username, password, realname, email, comment, salt, sysadmin_flag, creation_time, update_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?)").Prepare()
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -45,7 +47,8 @@ func Register(user models.User) (int64, error) {
return 0, err return 0, err
} }
r, err := p.Exec(user.Username, utils.Encrypt(user.Password, salt), user.Realname, user.Email, user.Comment, salt) now := time.Now()
r, err := p.Exec(user.Username, utils.Encrypt(user.Password, salt), user.Realname, user.Email, user.Comment, salt, user.HasAdminRole, now, now)
if err != nil { if err != nil {
return 0, err return 0, err

View File

@ -16,37 +16,57 @@
package dao package dao
import ( import (
"fmt"
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
"github.com/astaxie/beego/orm" "github.com/astaxie/beego/orm"
) )
type role int
// Start from 2 to guarantee the compatibility with former code
const (
ProjectAdmin role = 2
Developer = 3
Guest = 4
)
var roleList = make(map[role]*models.Role)
// IntToRole is used to convert int to role.
func IntToRole(i int) (r role, err error) {
switch i {
case 2:
r = ProjectAdmin
case 3:
r = Developer
case 4:
r = Guest
default:
err = fmt.Errorf("no role is correspondent with the input: %d", i)
}
return
}
// GetUserProjectRoles returns roles that the user has according to the project. // GetUserProjectRoles returns roles that the user has according to the project.
func GetUserProjectRoles(userQuery models.User, projectID int64) ([]models.Role, error) { func GetUserProjectRoles(userQuery models.User, projectID int64) ([]models.Role, error) {
o := orm.NewOrm() o := orm.NewOrm()
sql := `select distinct r.role_id, r.role_code, r.name sql := `select *
from role r from role
left join project_role pr on r.role_id = pr.role_id where role_id =
left join user_project_role upr on pr.pr_id = upr.pr_id (
left join user u on u.user_id = upr.user_id select role
where u.deleted = 0 from project_member
and u.user_id = ? ` where project_id = ? and user_id = ?
)`
queryParam := make([]interface{}, 1) queryParam := make([]interface{}, 1)
queryParam = append(queryParam, userQuery.UserID) queryParam = append(queryParam, userQuery.UserID)
if projectID > 0 {
sql += ` and pr.project_id = ? `
queryParam = append(queryParam, projectID)
}
if userQuery.RoleID > 0 {
sql += ` and r.role_id = ? `
queryParam = append(queryParam, userQuery.RoleID)
}
var roleList []models.Role var roleList []models.Role
_, err := o.Raw(sql, queryParam).QueryRows(&roleList) _, err := o.Raw(sql, projectID, userQuery.UserID).QueryRows(&roleList)
if err != nil { if err != nil {
return nil, err return nil, err
@ -56,11 +76,54 @@ func GetUserProjectRoles(userQuery models.User, projectID int64) ([]models.Role,
// IsAdminRole returns whether the user is admin. // IsAdminRole returns whether the user is admin.
func IsAdminRole(userID int) (bool, error) { func IsAdminRole(userID int) (bool, error) {
//role_id == 1 means the user is system admin
userQuery := models.User{UserID: userID, RoleID: models.SYSADMIN} user, err := GetUser(models.User{UserID: userID})
adminRoleList, err := GetUserProjectRoles(userQuery, 0)
if err != nil { if err != nil {
return false, err return false, err
} }
return len(adminRoleList) > 0, nil
if user == nil {
return false, nil
}
return user.HasAdminRole == 1, nil
}
func getRole(r role) (*models.Role, error) {
if roleList[r] != nil {
return roleList[r], nil
}
o := orm.NewOrm()
var roles []*models.Role
sql := "select role_id, role_code, name, role_mask from role"
_, err := o.Raw(sql).QueryRows(&roles)
if err != nil {
return nil, err
}
for _, rr := range roles {
if rr.RoleCode == "MDRWS" {
roleList[ProjectAdmin] = rr
continue
}
if rr.RoleCode == "RWS" {
roleList[Developer] = rr
continue
}
if rr.RoleCode == "RS" {
roleList[Guest] = rr
continue
}
}
if roleList[r] == nil {
return nil, fmt.Errorf("unsupported role type: %v", r)
}
return roleList[r], nil
} }

View File

@ -22,8 +22,8 @@ import (
"github.com/vmware/harbor/models" "github.com/vmware/harbor/models"
"github.com/vmware/harbor/utils" "github.com/vmware/harbor/utils"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm" "github.com/astaxie/beego/orm"
"github.com/vmware/harbor/utils/log"
) )
// GetUser ... // GetUser ...
@ -31,12 +31,8 @@ func GetUser(query models.User) (*models.User, error) {
o := orm.NewOrm() o := orm.NewOrm()
sql := `select user_id, username, email, realname, reset_uuid, salt, sql := `select user_id, username, email, realname, comment, reset_uuid, salt,
ifnull((select pr.role_id sysadmin_flag, creation_time, update_time
from project_role pr
left join user_project_role upr on upr.pr_id = pr.pr_id
where pr.role_id = 1
and upr.user_id = u.user_id),0) as has_admin_role
from user u from user u
where deleted = 0 ` where deleted = 0 `
queryParam := make([]interface{}, 1) queryParam := make([]interface{}, 1)
@ -60,51 +56,52 @@ func GetUser(query models.User) (*models.User, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} else if n == 0 {
return nil, nil
} else {
return &u[0], nil
} }
if n == 0 {
return nil, nil
}
return &u[0], nil
} }
// LoginByDb is used for user to login with database auth mode. // LoginByDb is used for user to login with database auth mode.
func LoginByDb(auth models.AuthModel) (*models.User, error) { func LoginByDb(auth models.AuthModel) (*models.User, error) {
query := models.User{Username: auth.Principal, Email: auth.Principal}
o := orm.NewOrm() o := orm.NewOrm()
var u []models.User
n, err := o.Raw(`select username from user where (username = ? or email = ?)`, query.Username, query.Email).QueryRows(&u) var users []models.User
n, err := o.Raw(`select * from user where (username = ? or email = ?)`,
auth.Principal, auth.Principal).QueryRows(&users)
if err != nil { if err != nil {
return nil, err return nil, err
} else if n == 0 { }
beego.Warning("User does not exist. Principal:", auth.Principal) if n == 0 {
return nil, nil return nil, nil
} else {
u[0].Password = auth.Password
return CheckUserPassword(u[0])
} }
user := users[0]
if user.Password != utils.Encrypt(auth.Password, user.Salt) {
return nil, nil
}
return &user, nil
} }
// ListUsers lists all users according to different conditions. // ListUsers lists all users according to different conditions.
func ListUsers(query models.User) ([]models.User, error) { func ListUsers(query models.User) ([]models.User, error) {
o := orm.NewOrm() o := orm.NewOrm()
u := []models.User{} u := []models.User{}
sql := `select u.user_id, u.username, u.email, ifnull((select pr.role_id sql := `select user_id, username, email, realname, comment, reset_uuid, salt,
from project_role pr sysadmin_flag, creation_time, update_time
left join user_project_role upr on upr.pr_id = pr.pr_id
where pr.role_id = 1
and upr.user_id = u.user_id),0) as has_admin_role
from user u from user u
where u.deleted = 0 and u.user_id != 1 ` where u.deleted = 0 and u.user_id != 1 `
queryParam := make([]interface{}, 1) queryParam := make([]interface{}, 1)
if query.Username != "" { if query.Username != "" {
sql += ` and u.username like ? ` sql += ` and username like ? `
queryParam = append(queryParam, query.Username) queryParam = append(queryParam, query.Username)
} }
sql += ` order by u.user_id desc ` sql += ` order by user_id desc `
_, err := o.Raw(sql, queryParam).QueryRows(&u) _, err := o.Raw(sql, queryParam).QueryRows(&u)
return u, err return u, err
@ -112,59 +109,76 @@ func ListUsers(query models.User) ([]models.User, error) {
// ToggleUserAdminRole gives a user admim role. // ToggleUserAdminRole gives a user admim role.
func ToggleUserAdminRole(u models.User) error { func ToggleUserAdminRole(u models.User) error {
projectRole := models.ProjectRole{PrID: 1} //admin project role
o := orm.NewOrm() o := orm.NewOrm()
var pr []models.ProjectRole var user models.User
err := o.Raw(`select sysadmin_flag from user where user_id = ?`, u.UserID).QueryRow(&user)
n, err := o.Raw(`select user_id from user_project_role where user_id = ? and pr_id = ? `, u.UserID, projectRole.PrID).QueryRows(&pr)
if err != nil { if err != nil {
return err return err
} }
var sql string var sysAdminFlag int
if n == 0 { if user.HasAdminRole == 0 {
sql = `insert into user_project_role (user_id, pr_id) values (?, ?)` sysAdminFlag = 1
} else { } else {
sql = `delete from user_project_role where user_id = ? and pr_id = ?` sysAdminFlag = 0
} }
p, err := o.Raw(sql).Prepare() sql := `update user set sysadmin_flag = ? where user_id = ?`
r, err := o.Raw(sql, sysAdminFlag, u.UserID).Exec()
if err != nil { if err != nil {
return err return err
} }
defer p.Close()
_, err = p.Exec(u.UserID, projectRole.PrID)
if _, err := r.RowsAffected(); err != nil {
return err return err
}
return nil
} }
// ChangeUserPassword ... // ChangeUserPassword ...
func ChangeUserPassword(u models.User, oldPassword ...string) error { func ChangeUserPassword(u models.User, oldPassword ...string) (err error) {
o := orm.NewOrm() o := orm.NewOrm()
var err error
var r sql.Result var r sql.Result
if len(oldPassword) == 0 { if len(oldPassword) == 0 {
//In some cases, it may no need to check old password, just as Linux change password policies. //In some cases, it may no need to check old password, just as Linux change password policies.
_, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID).Exec() r, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID).Exec()
} else if len(oldPassword) == 1 { if err != nil {
return err
}
c, err := r.RowsAffected()
if err != nil {
return err
}
if c == 0 {
return errors.New("No record has been modified, change password failed.")
}
return nil
}
if len(oldPassword) == 1 {
r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID, utils.Encrypt(oldPassword[0], u.Salt)).Exec() r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID, utils.Encrypt(oldPassword[0], u.Salt)).Exec()
if err != nil { if err != nil {
return err return err
} }
count, err := r.RowsAffected() c, err := r.RowsAffected()
if err != nil { if err != nil {
return err return err
} }
if count == 0 { if c == 0 {
return errors.New("No record be changed, change password failed.") return errors.New("No record has been modified, change password failed.")
} }
} else {
return nil
}
return errors.New("Wrong numbers of params.") return errors.New("Wrong numbers of params.")
}
return err
} }
// ResetUserPassword ... // ResetUserPassword ...
@ -181,7 +195,7 @@ func ResetUserPassword(u models.User) error {
if count == 0 { if count == 0 {
return errors.New("No record be changed, reset password failed.") return errors.New("No record be changed, reset password failed.")
} }
return err return nil
} }
// UpdateUserResetUUID ... // UpdateUserResetUUID ...
@ -224,12 +238,14 @@ func CheckUserPassword(query models.User) (*models.User, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} else if n == 0 {
beego.Warning("User principal does not match password. Current:", currentUser)
return nil, nil
} else {
return &user[0], nil
} }
if n == 0 {
log.Warning("User principal does not match password. Current:", currentUser)
return nil, nil
}
return &user[0], nil
} }
// DeleteUser ... // DeleteUser ...

View File

@ -32,4 +32,6 @@ type Project struct {
Public int `orm:"column(public)"` Public int `orm:"column(public)"`
//This field does not have correspondent column in DB, this is just for UI to disable button //This field does not have correspondent column in DB, this is just for UI to disable button
Togglable bool Togglable bool
UpdateTime time.Time `orm:"update_time" json:"update_time"`
} }

View File

@ -15,6 +15,7 @@
package models package models
/*
const ( const (
//SYSADMIN system administrator //SYSADMIN system administrator
SYSADMIN = 1 SYSADMIN = 1
@ -25,14 +26,17 @@ const (
//GUEST guest //GUEST guest
GUEST = 4 GUEST = 4
) )
*/
// Role holds the details of a role. // Role holds the details of a role.
type Role struct { type Role struct {
RoleID int `json:"role_id" orm:"column(role_id)"` RoleID int `orm:"column(role_id)" json:"role_id"`
RoleCode string `json:"role_code" orm:"column(role_code)"` RoleCode string `orm:"column(role_code)" json:"role_code"`
Name string `json:"role_name" orm:"column(name)"` Name string `orm:"column(name)" json:"role_name"`
RoleMask int `orm:"role_mask" json:"role_mask"`
} }
/*
// ProjectRole holds information about the relationship of project and role. // ProjectRole holds information about the relationship of project and role.
type ProjectRole struct { type ProjectRole struct {
PrID int `orm:"column(pr_id)" json:"PrId"` PrID int `orm:"column(pr_id)" json:"PrId"`
@ -46,3 +50,4 @@ type UserProjectRole struct {
UserID int `orm:"column(user_id)" json:"UserId"` UserID int `orm:"column(user_id)" json:"UserId"`
PrID int64 `orm:"column(pr_id)" json:"PrId"` PrID int64 `orm:"column(pr_id)" json:"PrId"`
} }
*/

View File

@ -15,6 +15,10 @@
package models package models
import (
"time"
)
// User holds the details of a user. // User holds the details of a user.
type User struct { type User struct {
UserID int `orm:"column(user_id)" json:"UserId"` UserID int `orm:"column(user_id)" json:"UserId"`
@ -27,7 +31,10 @@ type User struct {
Rolename string Rolename string
RoleID int `json:"RoleId"` RoleID int `json:"RoleId"`
RoleList []Role RoleList []Role
HasAdminRole int HasAdminRole int `orm:"column(sysadmin_flag)"`
ResetUUID string `orm:"column(reset_uuid)" json:"ResetUuid"` ResetUUID string `orm:"column(reset_uuid)" json:"ResetUuid"`
Salt string `orm:"column(salt)"` Salt string `orm:"column(salt)"`
CreationTime time.Time `orm:"creation_time" json:"creation_time"`
UpdateTime time.Time `orm:"update_time" json:"update_time"`
} }