mirror of
https://github.com/goharbor/harbor.git
synced 2024-09-27 21:12:42 +02:00
Merge pull request #2316 from ywk253100/170512_project
Refactor project API
This commit is contained in:
commit
d45ef78eaf
@ -39,6 +39,17 @@ type BaseAPI struct {
|
|||||||
beego.Controller
|
beego.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStringFromPath gets the param from path and returns it as string
|
||||||
|
func (b *BaseAPI) GetStringFromPath(key string) string {
|
||||||
|
return b.Ctx.Input.Param(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt64FromPath gets the param from path and returns it as int64
|
||||||
|
func (b *BaseAPI) GetInt64FromPath(key string) (int64, error) {
|
||||||
|
value := b.Ctx.Input.Param(key)
|
||||||
|
return strconv.ParseInt(value, 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
// HandleNotFound ...
|
// HandleNotFound ...
|
||||||
func (b *BaseAPI) HandleNotFound(text string) {
|
func (b *BaseAPI) HandleNotFound(text string) {
|
||||||
log.Info(text)
|
log.Info(text)
|
||||||
|
@ -24,10 +24,9 @@ const (
|
|||||||
LDAPScopeOnelevel = "2"
|
LDAPScopeOnelevel = "2"
|
||||||
LDAPScopeSubtree = "3"
|
LDAPScopeSubtree = "3"
|
||||||
|
|
||||||
RoleSystemAdmin = 1
|
RoleProjectAdmin = 1
|
||||||
RoleProjectAdmin = 2
|
RoleDeveloper = 2
|
||||||
RoleDeveloper = 3
|
RoleGuest = 3
|
||||||
RoleGuest = 4
|
|
||||||
|
|
||||||
DeployModeStandAlone = "standalone"
|
DeployModeStandAlone = "standalone"
|
||||||
DeployModeIntegration = "integration"
|
DeployModeIntegration = "integration"
|
||||||
|
@ -801,32 +801,8 @@ func TestProjectPermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTotalOfUserRelevantProjects(t *testing.T) {
|
|
||||||
total, err := GetTotalOfUserRelevantProjects(currentUser.UserID, "")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to get total of user relevant projects: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if total != 1 {
|
|
||||||
t.Errorf("unexpected total: %d != 1", total)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetUserRelevantProjects(t *testing.T) {
|
|
||||||
projects, err := GetUserRelevantProjects(currentUser.UserID, "")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in GetUserRelevantProjects: %v", err)
|
|
||||||
}
|
|
||||||
if len(projects) != 1 {
|
|
||||||
t.Errorf("Expected length of relevant projects is 1, but actual: %d, the projects: %+v", len(projects), projects)
|
|
||||||
}
|
|
||||||
if projects[0].Name != projectName {
|
|
||||||
t.Errorf("Expected project name in the list: %s, actual: %s", projectName, projects[1].Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetTotalOfProjects(t *testing.T) {
|
func TestGetTotalOfProjects(t *testing.T) {
|
||||||
total, err := GetTotalOfProjects("")
|
total, err := GetTotalOfProjects(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to get total of projects: %v", err)
|
t.Fatalf("failed to get total of projects: %v", err)
|
||||||
}
|
}
|
||||||
@ -837,7 +813,7 @@ func TestGetTotalOfProjects(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetProjects(t *testing.T) {
|
func TestGetProjects(t *testing.T) {
|
||||||
projects, err := GetProjects("")
|
projects, err := GetProjects(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in GetAllProjects: %v", err)
|
t.Errorf("Error occurred in GetAllProjects: %v", err)
|
||||||
}
|
}
|
||||||
@ -850,7 +826,10 @@ func TestGetProjects(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPublicProjects(t *testing.T) {
|
func TestGetPublicProjects(t *testing.T) {
|
||||||
projects, err := GetProjects("", 1)
|
value := true
|
||||||
|
projects, err := GetProjects(&models.QueryParam{
|
||||||
|
Public: &value,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in getProjects: %v", err)
|
t.Errorf("Error occurred in getProjects: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package dao
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -159,7 +160,7 @@ func ToggleProjectPublicity(projectID int64, publicity int) error {
|
|||||||
// which satisfies the following conditions:
|
// which satisfies the following conditions:
|
||||||
// 1. the project is not deleted
|
// 1. the project is not deleted
|
||||||
// 2. the prject is public or the user is a member of the project
|
// 2. the prject is public or the user is a member of the project
|
||||||
func SearchProjects(userID int) ([]models.Project, error) {
|
func SearchProjects(userID int) ([]*models.Project, error) {
|
||||||
o := GetOrmer()
|
o := GetOrmer()
|
||||||
|
|
||||||
sql :=
|
sql :=
|
||||||
@ -171,7 +172,7 @@ func SearchProjects(userID int) ([]models.Project, error) {
|
|||||||
where (pm.user_id = ? or p.public = 1)
|
where (pm.user_id = ? or p.public = 1)
|
||||||
and p.deleted = 0 `
|
and p.deleted = 0 `
|
||||||
|
|
||||||
var projects []models.Project
|
var projects []*models.Project
|
||||||
|
|
||||||
if _, err := o.Raw(sql, userID).QueryRows(&projects); err != nil {
|
if _, err := o.Raw(sql, userID).QueryRows(&projects); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -180,101 +181,146 @@ func SearchProjects(userID int) ([]models.Project, error) {
|
|||||||
return projects, nil
|
return projects, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetTotalOfUserRelevantProjects returns the total count of
|
// GetTotalOfProjects returns the total count of projects
|
||||||
// user relevant projects
|
// according to the query conditions
|
||||||
func GetTotalOfUserRelevantProjects(userID int, projectName string) (int64, error) {
|
func GetTotalOfProjects(query *models.QueryParam) (int64, error) {
|
||||||
o := GetOrmer()
|
|
||||||
sql := `select count(*) from project p
|
|
||||||
left join project_member pm
|
|
||||||
on p.project_id = pm.project_id
|
|
||||||
where p.deleted = 0 and pm.user_id= ?`
|
|
||||||
|
|
||||||
queryParam := []interface{}{}
|
var (
|
||||||
queryParam = append(queryParam, userID)
|
owner string
|
||||||
if projectName != "" {
|
name string
|
||||||
sql += " and p.name like ? "
|
public *bool
|
||||||
queryParam = append(queryParam, "%"+escape(projectName)+"%")
|
member string
|
||||||
|
role int
|
||||||
|
)
|
||||||
|
|
||||||
|
if query != nil {
|
||||||
|
owner = query.Owner
|
||||||
|
name = query.Name
|
||||||
|
public = query.Public
|
||||||
|
if query.Member != nil {
|
||||||
|
member = query.Member.Name
|
||||||
|
role = query.Member.Role
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var total int64
|
sql, params := queryConditions(owner, name, public, member, role)
|
||||||
err := o.Raw(sql, queryParam).QueryRow(&total)
|
|
||||||
|
|
||||||
|
sql = `select count(*) ` + sql
|
||||||
|
|
||||||
|
var total int64
|
||||||
|
err := GetOrmer().Raw(sql, params).QueryRow(&total)
|
||||||
return total, err
|
return total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserRelevantProjects returns the user relevant projects
|
// GetProjects returns a project list according to the query conditions
|
||||||
// args[0]: public, args[1]: limit, args[2]: offset
|
func GetProjects(query *models.QueryParam) ([]*models.Project, error) {
|
||||||
func GetUserRelevantProjects(userID int, projectName string, args ...int64) ([]models.Project, error) {
|
|
||||||
return getProjects(userID, projectName, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTotalOfProjects returns the total count of projects
|
var (
|
||||||
func GetTotalOfProjects(name string, public ...int) (int64, error) {
|
owner string
|
||||||
qs := GetOrmer().
|
name string
|
||||||
QueryTable(new(models.Project)).
|
public *bool
|
||||||
Filter("Deleted", 0)
|
member string
|
||||||
|
role int
|
||||||
|
page int64
|
||||||
|
size int64
|
||||||
|
)
|
||||||
|
|
||||||
if len(name) > 0 {
|
if query != nil {
|
||||||
qs = qs.Filter("Name__icontains", name)
|
owner = query.Owner
|
||||||
|
name = query.Name
|
||||||
|
public = query.Public
|
||||||
|
if query.Member != nil {
|
||||||
|
member = query.Member.Name
|
||||||
|
role = query.Member.Role
|
||||||
|
}
|
||||||
|
if query.Pagination != nil {
|
||||||
|
page = query.Pagination.Page
|
||||||
|
size = query.Pagination.Size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(public) > 0 {
|
sql, params := queryConditions(owner, name, public, member, role)
|
||||||
qs = qs.Filter("Public", public[0])
|
|
||||||
|
sql = `select distinct p.project_id, p.name, p.public, p.owner_id,
|
||||||
|
p.creation_time, p.update_time ` + sql
|
||||||
|
if size > 0 {
|
||||||
|
sql += ` limit ?`
|
||||||
|
params = append(params, size)
|
||||||
|
|
||||||
|
if page > 0 {
|
||||||
|
sql += ` offset ?`
|
||||||
|
params = append(params, (page-1)*size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return qs.Count()
|
var projects []*models.Project
|
||||||
}
|
_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
|
||||||
|
|
||||||
// GetProjects returns project list
|
|
||||||
// args[0]: public, args[1]: limit, args[2]: offset
|
|
||||||
func GetProjects(name string, args ...int64) ([]models.Project, error) {
|
|
||||||
return getProjects(0, name, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProjects(userID int, name string, args ...int64) ([]models.Project, error) {
|
|
||||||
projects := []models.Project{}
|
|
||||||
|
|
||||||
o := GetOrmer()
|
|
||||||
sql := ""
|
|
||||||
queryParam := []interface{}{}
|
|
||||||
|
|
||||||
if userID != 0 { //get user's projects
|
|
||||||
sql = `select distinct p.project_id, p.owner_id, p.name,
|
|
||||||
p.creation_time, p.update_time, p.public, pm.role role
|
|
||||||
from project p
|
|
||||||
left join project_member pm
|
|
||||||
on p.project_id = pm.project_id
|
|
||||||
where p.deleted = 0 and pm.user_id= ?`
|
|
||||||
queryParam = append(queryParam, userID)
|
|
||||||
} else { // get all projects
|
|
||||||
sql = `select * from project p where p.deleted = 0 `
|
|
||||||
}
|
|
||||||
|
|
||||||
if name != "" {
|
|
||||||
sql += ` and p.name like ? `
|
|
||||||
queryParam = append(queryParam, "%"+escape(name)+"%")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch len(args) {
|
|
||||||
case 1:
|
|
||||||
sql += ` and p.public = ?`
|
|
||||||
queryParam = append(queryParam, args[0])
|
|
||||||
sql += ` order by p.name `
|
|
||||||
case 2:
|
|
||||||
sql += ` order by p.name `
|
|
||||||
sql = paginateForRawSQL(sql, args[0], args[1])
|
|
||||||
case 3:
|
|
||||||
sql += ` and p.public = ?`
|
|
||||||
queryParam = append(queryParam, args[0])
|
|
||||||
sql += ` order by p.name `
|
|
||||||
sql = paginateForRawSQL(sql, args[1], args[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := o.Raw(sql, queryParam).QueryRows(&projects)
|
|
||||||
|
|
||||||
return projects, err
|
return projects, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func queryConditions(owner, name string, public *bool, member string,
|
||||||
|
role int) (string, []interface{}) {
|
||||||
|
params := []interface{}{}
|
||||||
|
|
||||||
|
sql := ` from project p`
|
||||||
|
|
||||||
|
if len(owner) != 0 {
|
||||||
|
sql += ` join user u1
|
||||||
|
on p.owner_id = u1.user_id`
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(member) != 0 {
|
||||||
|
sql += ` join project_member pm
|
||||||
|
on p.project_id = pm.project_id
|
||||||
|
join user u2
|
||||||
|
on pm.user_id=u2.user_id`
|
||||||
|
}
|
||||||
|
sql += ` where p.deleted=0`
|
||||||
|
|
||||||
|
if len(owner) != 0 {
|
||||||
|
sql += ` and u1.username=?`
|
||||||
|
params = append(params, owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(name) != 0 {
|
||||||
|
sql += ` and p.name like ?`
|
||||||
|
params = append(params, "%"+escape(name)+"%")
|
||||||
|
}
|
||||||
|
|
||||||
|
if public != nil {
|
||||||
|
sql += ` and p.public = ?`
|
||||||
|
if *public {
|
||||||
|
params = append(params, 1)
|
||||||
|
} else {
|
||||||
|
params = append(params, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(member) != 0 {
|
||||||
|
sql += ` and u2.username=?`
|
||||||
|
params = append(params, member)
|
||||||
|
|
||||||
|
if role > 0 {
|
||||||
|
sql += ` and pm.role = ?`
|
||||||
|
roleID := 0
|
||||||
|
switch role {
|
||||||
|
case common.RoleProjectAdmin:
|
||||||
|
roleID = 1
|
||||||
|
case common.RoleDeveloper:
|
||||||
|
roleID = 2
|
||||||
|
case common.RoleGuest:
|
||||||
|
roleID = 3
|
||||||
|
|
||||||
|
}
|
||||||
|
params = append(params, roleID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sql += ` order by p.name`
|
||||||
|
|
||||||
|
return sql, params
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteProject ...
|
// DeleteProject ...
|
||||||
func DeleteProject(id int64) error {
|
func DeleteProject(id int64) error {
|
||||||
project, err := GetProjectByID(id)
|
project, err := GetProjectByID(id)
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// AccessLog holds information about logs which are used to record the actions that user take to the resourses.
|
// AccessLog holds information about logs which are used to record the actions that user take to the resourses.
|
||||||
|
// TODO remove useless attrs
|
||||||
type AccessLog struct {
|
type AccessLog struct {
|
||||||
LogID int `orm:"pk;auto;column(log_id)" json:"log_id"`
|
LogID int `orm:"pk;auto;column(log_id)" json:"log_id"`
|
||||||
Username string `orm:"column(username)" json:"username"`
|
Username string `orm:"column(username)" json:"username"`
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Project holds the details of a project.
|
// Project holds the details of a project.
|
||||||
|
// TODO remove useless attrs
|
||||||
type Project struct {
|
type Project struct {
|
||||||
ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"`
|
ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"`
|
||||||
OwnerID int `orm:"column(owner_id)" json:"owner_id"`
|
OwnerID int `orm:"column(owner_id)" json:"owner_id"`
|
||||||
@ -39,7 +40,7 @@ type Project struct {
|
|||||||
|
|
||||||
// ProjectSorter holds an array of projects
|
// ProjectSorter holds an array of projects
|
||||||
type ProjectSorter struct {
|
type ProjectSorter struct {
|
||||||
Projects []Project
|
Projects []*Project
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the length of array in ProjectSorter
|
// Len returns the length of array in ProjectSorter
|
||||||
@ -56,3 +57,34 @@ func (ps *ProjectSorter) Less(i, j int) bool {
|
|||||||
func (ps *ProjectSorter) Swap(i, j int) {
|
func (ps *ProjectSorter) Swap(i, j int) {
|
||||||
ps.Projects[i], ps.Projects[j] = ps.Projects[j], ps.Projects[i]
|
ps.Projects[i], ps.Projects[j] = ps.Projects[j], ps.Projects[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryParam can be used to set query parameters when listing projects.
|
||||||
|
// The query condition will be set in the query if its corresponding field
|
||||||
|
// is not nil. Leave it empty if you don't want to apply this condition.
|
||||||
|
//
|
||||||
|
// e.g.
|
||||||
|
// List all projects: query := nil
|
||||||
|
// List all public projects: query := &QueryParam{Public: true}
|
||||||
|
// List projects the owner of which is user1: query := &QueryParam{Owner:"user1"}
|
||||||
|
// List all public projects the owner of which is user1: query := &QueryParam{Owner:"user1",Public:true}
|
||||||
|
// List projects which user1 is member of: query := &QueryParam{Member:&Member{Name:"user1"}}
|
||||||
|
// List projects which user1 is the project admin : query := &QueryParam{Memeber:&Member{Name:"user1",Role:1}}
|
||||||
|
type QueryParam struct {
|
||||||
|
Name string // the name of project
|
||||||
|
Owner string // the username of project owner
|
||||||
|
Public *bool // the project is public or not, can be ture, false and nil
|
||||||
|
Member *Member // the member of project
|
||||||
|
Pagination *Pagination // pagination information
|
||||||
|
}
|
||||||
|
|
||||||
|
// Member fitler by member's username and role
|
||||||
|
type Member struct {
|
||||||
|
Name string // the username of member
|
||||||
|
Role int // the role of the member has to the project
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pagination ...
|
||||||
|
type Pagination struct {
|
||||||
|
Page int64
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@ package rbac
|
|||||||
import (
|
import (
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
"github.com/vmware/harbor/src/ui/projectmanager"
|
"github.com/vmware/harbor/src/ui/projectmanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -60,12 +61,25 @@ func (s *SecurityContext) IsSysAdmin() bool {
|
|||||||
// HasReadPerm returns whether the user has read permission to the project
|
// HasReadPerm returns whether the user has read permission to the project
|
||||||
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
||||||
// not exist
|
// not exist
|
||||||
if !s.pm.Exist(projectIDOrName) {
|
exist, err := s.pm.Exist(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to check the existence of project %v: %v",
|
||||||
|
projectIDOrName, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// public project
|
// public project
|
||||||
if s.pm.IsPublic(projectIDOrName) {
|
public, err := s.pm.IsPublic(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to check the public of project %v: %v",
|
||||||
|
projectIDOrName, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if public {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +93,13 @@ func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
roles := s.pm.GetRoles(s.GetUsername(), projectIDOrName)
|
roles, err := s.pm.GetRoles(s.GetUsername(), projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get roles of user %s to project %v: %v",
|
||||||
|
s.GetUsername(), projectIDOrName, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
switch role {
|
switch role {
|
||||||
case common.RoleProjectAdmin,
|
case common.RoleProjectAdmin,
|
||||||
@ -99,7 +119,14 @@ func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// project does not exist
|
// project does not exist
|
||||||
if !s.pm.Exist(projectIDOrName) {
|
exist, err := s.pm.Exist(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to check the existence of project %v: %v",
|
||||||
|
projectIDOrName, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +135,13 @@ func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
roles := s.pm.GetRoles(s.GetUsername(), projectIDOrName)
|
roles, err := s.pm.GetRoles(s.GetUsername(), projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get roles of user %s to project %v: %v",
|
||||||
|
s.GetUsername(), projectIDOrName, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
switch role {
|
switch role {
|
||||||
case common.RoleProjectAdmin,
|
case common.RoleProjectAdmin,
|
||||||
@ -127,7 +160,14 @@ func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// project does not exist
|
// project does not exist
|
||||||
if !s.pm.Exist(projectIDOrName) {
|
exist, err := s.pm.Exist(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to check the existence of project %v: %v",
|
||||||
|
projectIDOrName, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +176,13 @@ func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
roles := s.pm.GetRoles(s.GetUsername(), projectIDOrName)
|
roles, err := s.pm.GetRoles(s.GetUsername(), projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get roles of user %s to project %v: %v",
|
||||||
|
s.GetUsername(), projectIDOrName, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
switch role {
|
switch role {
|
||||||
case common.RoleProjectAdmin:
|
case common.RoleProjectAdmin:
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package rbac
|
package rbac
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -51,42 +52,67 @@ type fakePM struct {
|
|||||||
roles map[string][]int
|
roles map[string][]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakePM) IsPublic(projectIDOrName interface{}) bool {
|
func (f *fakePM) IsPublic(projectIDOrName interface{}) (bool, error) {
|
||||||
for _, project := range f.projects {
|
for _, project := range f.projects {
|
||||||
if project.Name == projectIDOrName.(string) {
|
if project.Name == projectIDOrName.(string) {
|
||||||
return project.Public == 1
|
return project.Public == 1, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
func (f *fakePM) GetRoles(username string, projectIDOrName interface{}) []int {
|
func (f *fakePM) GetRoles(username string, projectIDOrName interface{}) ([]int, error) {
|
||||||
return f.roles[projectIDOrName.(string)]
|
return f.roles[projectIDOrName.(string)], nil
|
||||||
}
|
}
|
||||||
func (f *fakePM) Get(projectIDOrName interface{}) *models.Project {
|
func (f *fakePM) Get(projectIDOrName interface{}) (*models.Project, error) {
|
||||||
for _, project := range f.projects {
|
for _, project := range f.projects {
|
||||||
if project.Name == projectIDOrName.(string) {
|
if project.Name == projectIDOrName.(string) {
|
||||||
return project
|
return project, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func (f *fakePM) Exist(projectIDOrName interface{}) bool {
|
func (f *fakePM) Exist(projectIDOrName interface{}) (bool, error) {
|
||||||
for _, project := range f.projects {
|
for _, project := range f.projects {
|
||||||
if project.Name == projectIDOrName.(string) {
|
if project.Name == projectIDOrName.(string) {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nil implement
|
// nil implement
|
||||||
func (f *fakePM) GetPublic() []models.Project {
|
func (f *fakePM) GetPublic() ([]*models.Project, error) {
|
||||||
return []models.Project{}
|
return []*models.Project{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nil implement
|
// nil implement
|
||||||
func (f *fakePM) GetByMember(username string) []models.Project {
|
func (f *fakePM) GetByMember(username string) ([]*models.Project, error) {
|
||||||
return []models.Project{}
|
return []*models.Project{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil implement
|
||||||
|
func (f *fakePM) Create(*models.Project) (int64, error) {
|
||||||
|
return 0, fmt.Errorf("not support")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil implement
|
||||||
|
func (f *fakePM) Delete(projectIDOrName interface{}) error {
|
||||||
|
return fmt.Errorf("not support")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil implement
|
||||||
|
func (f *fakePM) Update(projectIDOrName interface{}, project *models.Project) error {
|
||||||
|
return fmt.Errorf("not support")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil implement
|
||||||
|
func (f *fakePM) GetAll(*models.QueryParam) ([]*models.Project, error) {
|
||||||
|
return []*models.Project{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil implement
|
||||||
|
func (f *fakePM) GetTotal(*models.QueryParam) (int64, error) {
|
||||||
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsAuthenticated(t *testing.T) {
|
func TestIsAuthenticated(t *testing.T) {
|
||||||
|
@ -90,7 +90,7 @@ func (d *Deleter) enter() (string, error) {
|
|||||||
|
|
||||||
// delete repository
|
// delete repository
|
||||||
if len(d.tags) == 0 {
|
if len(d.tags) == 0 {
|
||||||
u := url + d.repository + "/tags"
|
u := url + d.repository
|
||||||
if err := del(u, d.dstUsr, d.dstPwd, d.insecure); err != nil {
|
if err := del(u, d.dstUsr, d.dstPwd, d.insecure); err != nil {
|
||||||
if err == errNotFound {
|
if err == errNotFound {
|
||||||
d.logger.Warningf("repository %s does not exist on %s", d.repository, d.dstURL)
|
d.logger.Warningf("repository %s does not exist on %s", d.repository, d.dstURL)
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common/api"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
@ -31,10 +31,8 @@ import (
|
|||||||
|
|
||||||
// ProjectAPI handles request to /api/projects/{} /api/projects/{}/logs
|
// ProjectAPI handles request to /api/projects/{} /api/projects/{}/logs
|
||||||
type ProjectAPI struct {
|
type ProjectAPI struct {
|
||||||
api.BaseAPI
|
BaseController
|
||||||
userID int
|
project *models.Project
|
||||||
projectID int64
|
|
||||||
projectName string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type projectReq struct {
|
type projectReq struct {
|
||||||
@ -49,33 +47,41 @@ const dupProjectPattern = `Duplicate entry '\w+' for key 'name'`
|
|||||||
|
|
||||||
// Prepare validates the URL and the user
|
// Prepare validates the URL and the user
|
||||||
func (p *ProjectAPI) Prepare() {
|
func (p *ProjectAPI) Prepare() {
|
||||||
idStr := p.Ctx.Input.Param(":id")
|
p.BaseController.Prepare()
|
||||||
if len(idStr) > 0 {
|
if len(p.GetStringFromPath(":id")) != 0 {
|
||||||
var err error
|
id, err := p.GetInt64FromPath(":id")
|
||||||
p.projectID, err = strconv.ParseInt(idStr, 10, 64)
|
if err != nil || id <= 0 {
|
||||||
if err != nil {
|
text := "invalid project ID: "
|
||||||
log.Errorf("Error parsing project id: %s, error: %v", idStr, err)
|
if err != nil {
|
||||||
p.CustomAbort(http.StatusBadRequest, "invalid project id")
|
text += err.Error()
|
||||||
|
} else {
|
||||||
|
text += fmt.Sprintf("%d", id)
|
||||||
|
}
|
||||||
|
p.HandleBadRequest(text)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err := dao.GetProjectByID(p.projectID)
|
project, err := p.ProjectMgr.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get project %d: %v", p.projectID, err)
|
p.HandleInternalServerError(fmt.Sprintf("failed to get project %d: %v",
|
||||||
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
id, err))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if project == nil {
|
if project == nil {
|
||||||
p.CustomAbort(http.StatusNotFound, fmt.Sprintf("project does not exist, id: %v", p.projectID))
|
p.HandleNotFound(fmt.Sprintf("project %d not found", id))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
p.projectName = project.Name
|
|
||||||
|
p.project = project
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post ...
|
// Post ...
|
||||||
func (p *ProjectAPI) Post() {
|
func (p *ProjectAPI) Post() {
|
||||||
p.userID = p.ValidateUser()
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
isSysAdmin, err := dao.IsAdminRole(p.userID)
|
p.HandleUnauthorized()
|
||||||
if err != nil {
|
return
|
||||||
log.Errorf("Failed to check admin role: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onlyAdmin, err := config.OnlyAdminCreateProject()
|
onlyAdmin, err := config.OnlyAdminCreateProject()
|
||||||
@ -83,31 +89,36 @@ func (p *ProjectAPI) Post() {
|
|||||||
log.Errorf("failed to determine whether only admin can create projects: %v", err)
|
log.Errorf("failed to determine whether only admin can create projects: %v", err)
|
||||||
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||||
}
|
}
|
||||||
if !isSysAdmin && onlyAdmin {
|
if onlyAdmin && !p.SecurityCtx.IsSysAdmin() {
|
||||||
log.Errorf("Only sys admin can create project")
|
log.Errorf("Only sys admin can create project")
|
||||||
p.RenderError(http.StatusForbidden, "Only system admin can create project")
|
p.RenderError(http.StatusForbidden, "Only system admin can create project")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var req projectReq
|
var pro projectReq
|
||||||
p.DecodeJSONReq(&req)
|
p.DecodeJSONReq(&pro)
|
||||||
public := req.Public
|
err = validateProjectReq(pro)
|
||||||
err = validateProjectReq(req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Invalid project request, error: %v", err)
|
log.Errorf("Invalid project request, error: %v", err)
|
||||||
p.RenderError(http.StatusBadRequest, fmt.Sprintf("invalid request: %v", err))
|
p.RenderError(http.StatusBadRequest, fmt.Sprintf("invalid request: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
projectName := req.ProjectName
|
|
||||||
exist, err := dao.ProjectExists(projectName)
|
exist, err := p.ProjectMgr.Exist(pro.ProjectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error happened checking project existence in db, error: %v, project name: %s", err, projectName)
|
p.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
|
||||||
|
pro.ProjectName, err))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if exist {
|
if exist {
|
||||||
p.RenderError(http.StatusConflict, "")
|
p.RenderError(http.StatusConflict, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
project := models.Project{OwnerID: p.userID, Name: projectName, CreationTime: time.Now(), Public: public}
|
|
||||||
projectID, err := dao.AddProject(project)
|
projectID, err := p.ProjectMgr.Create(&models.Project{
|
||||||
|
Name: pro.ProjectName,
|
||||||
|
Public: pro.Public,
|
||||||
|
OwnerName: p.SecurityCtx.GetUsername(),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to add project, error: %v", err)
|
log.Errorf("Failed to add project, error: %v", err)
|
||||||
dup, _ := regexp.MatchString(dupProjectPattern, err.Error())
|
dup, _ := regexp.MatchString(dupProjectPattern, err.Error())
|
||||||
@ -120,26 +131,16 @@ func (p *ProjectAPI) Post() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
user, err := dao.GetUser(models.User{
|
if err = dao.AddAccessLog(
|
||||||
UserID: p.userID,
|
models.AccessLog{
|
||||||
})
|
Username: p.SecurityCtx.GetUsername(),
|
||||||
if err != nil {
|
ProjectID: projectID,
|
||||||
log.Errorf("failed to get user by ID %d: %v", p.userID, err)
|
RepoName: pro.ProjectName + "/",
|
||||||
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
RepoTag: "N/A",
|
||||||
}
|
Operation: "create",
|
||||||
|
OpTime: time.Now(),
|
||||||
accessLog := models.AccessLog{
|
}); err != nil {
|
||||||
Username: user.Username,
|
|
||||||
ProjectID: projectID,
|
|
||||||
RepoName: project.Name + "/",
|
|
||||||
RepoTag: "N/A",
|
|
||||||
GUID: "N/A",
|
|
||||||
Operation: "create",
|
|
||||||
OpTime: time.Now(),
|
|
||||||
}
|
|
||||||
if err = dao.AddAccessLog(accessLog); err != nil {
|
|
||||||
log.Errorf("failed to add access log: %v", err)
|
log.Errorf("failed to add access log: %v", err)
|
||||||
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -148,95 +149,84 @@ func (p *ProjectAPI) Post() {
|
|||||||
|
|
||||||
// Head ...
|
// Head ...
|
||||||
func (p *ProjectAPI) Head() {
|
func (p *ProjectAPI) Head() {
|
||||||
projectName := p.GetString("project_name")
|
name := p.GetString("project_name")
|
||||||
if len(projectName) == 0 {
|
if len(name) == 0 {
|
||||||
p.CustomAbort(http.StatusBadRequest, "project_name is needed")
|
p.HandleBadRequest("project_name is needed")
|
||||||
}
|
return
|
||||||
|
}
|
||||||
project, err := dao.GetProjectByName(projectName)
|
|
||||||
if err != nil {
|
project, err := p.ProjectMgr.Get(name)
|
||||||
log.Errorf("error occurred in GetProjectByName: %v", err)
|
if err != nil {
|
||||||
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
p.HandleInternalServerError(fmt.Sprintf("failed to get project %s: %v",
|
||||||
}
|
name, err))
|
||||||
|
|
||||||
// only public project can be Headed by user without login
|
|
||||||
if project != nil && project.Public == 1 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = p.ValidateUser()
|
|
||||||
if project == nil {
|
if project == nil {
|
||||||
p.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
|
p.HandleNotFound(fmt.Sprintf("project %s not found", name))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get ...
|
// Get ...
|
||||||
func (p *ProjectAPI) Get() {
|
func (p *ProjectAPI) Get() {
|
||||||
project, err := dao.GetProjectByID(p.projectID)
|
if p.project.Public == 0 {
|
||||||
if err != nil {
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
log.Errorf("failed to get project %d: %v", p.projectID, err)
|
p.HandleUnauthorized()
|
||||||
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if project.Public == 0 {
|
if !p.SecurityCtx.HasReadPerm(p.project.ProjectID) {
|
||||||
userID := p.ValidateUser()
|
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||||
if !checkProjectPermission(userID, p.projectID) {
|
return
|
||||||
p.CustomAbort(http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Data["json"] = project
|
p.Data["json"] = p.project
|
||||||
p.ServeJSON()
|
p.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete ...
|
// Delete ...
|
||||||
func (p *ProjectAPI) Delete() {
|
func (p *ProjectAPI) Delete() {
|
||||||
if p.projectID == 0 {
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
p.CustomAbort(http.StatusBadRequest, "project ID is required")
|
p.HandleUnauthorized()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := p.ValidateUser()
|
if !p.SecurityCtx.HasAllPerm(p.project.ProjectID) {
|
||||||
|
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||||
if !hasProjectAdminRole(userID, p.projectID) {
|
return
|
||||||
p.CustomAbort(http.StatusForbidden, "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
contains, err := projectContainsRepo(p.projectName)
|
contains, err := projectContainsRepo(p.project.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to check whether project %s contains any repository: %v", p.projectName, err)
|
log.Errorf("failed to check whether project %s contains any repository: %v", p.project.Name, err)
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
p.CustomAbort(http.StatusInternalServerError, "")
|
||||||
}
|
}
|
||||||
if contains {
|
if contains {
|
||||||
p.CustomAbort(http.StatusPreconditionFailed, "project contains repositores, can not be deleted")
|
p.CustomAbort(http.StatusPreconditionFailed, "project contains repositores, can not be deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
contains, err = projectContainsPolicy(p.projectID)
|
contains, err = projectContainsPolicy(p.project.ProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to check whether project %s contains any policy: %v", p.projectName, err)
|
log.Errorf("failed to check whether project %s contains any policy: %v", p.project.Name, err)
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
p.CustomAbort(http.StatusInternalServerError, "")
|
||||||
}
|
}
|
||||||
if contains {
|
if contains {
|
||||||
p.CustomAbort(http.StatusPreconditionFailed, "project contains policies, can not be deleted")
|
p.CustomAbort(http.StatusPreconditionFailed, "project contains policies, can not be deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = dao.DeleteProject(p.projectID); err != nil {
|
if err = p.ProjectMgr.Delete(p.project.ProjectID); err != nil {
|
||||||
log.Errorf("failed to delete project %d: %v", p.projectID, err)
|
p.HandleInternalServerError(
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
fmt.Sprintf("failed to delete project %d: %v", p.project.ProjectID, err))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
user, err := dao.GetUser(models.User{
|
|
||||||
UserID: userID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get user by ID %d: %v", userID, err)
|
|
||||||
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := dao.AddAccessLog(models.AccessLog{
|
if err := dao.AddAccessLog(models.AccessLog{
|
||||||
Username: user.Username,
|
Username: p.SecurityCtx.GetUsername(),
|
||||||
ProjectID: p.projectID,
|
ProjectID: p.project.ProjectID,
|
||||||
RepoName: p.projectName + "/",
|
RepoName: p.project.Name + "/",
|
||||||
RepoTag: "N/A",
|
RepoTag: "N/A",
|
||||||
Operation: "delete",
|
Operation: "delete",
|
||||||
OpTime: time.Now(),
|
OpTime: time.Now(),
|
||||||
@ -265,139 +255,134 @@ func projectContainsPolicy(id int64) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List ...
|
// List ...
|
||||||
|
// TODO refacter pattern to:
|
||||||
|
// /api/repositories?owner=xxx&name=xxx&public=true&member=xxx&role=1&page=1&size=3
|
||||||
func (p *ProjectAPI) List() {
|
func (p *ProjectAPI) List() {
|
||||||
var total int64
|
query := &models.QueryParam{}
|
||||||
var public int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
page, pageSize := p.GetPaginationParams()
|
query.Name = p.GetString("project_name")
|
||||||
|
public := p.GetString("is_public")
|
||||||
var projectList []models.Project
|
if len(public) != 0 {
|
||||||
projectName := p.GetString("project_name")
|
if public != "0" && public != "1" {
|
||||||
|
p.HandleBadRequest("is_public should be 0 or 1")
|
||||||
isPublic := p.GetString("is_public")
|
return
|
||||||
if len(isPublic) > 0 {
|
}
|
||||||
public, err = strconv.Atoi(isPublic)
|
if public == "1" {
|
||||||
if err != nil {
|
t := true
|
||||||
log.Errorf("Error parsing public property: %v, error: %v", isPublic, err)
|
query.Public = &t
|
||||||
p.CustomAbort(http.StatusBadRequest, "invalid project Id")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isAdmin := false
|
|
||||||
if public == 1 {
|
if query.Public == nil || *query.Public == false {
|
||||||
total, err = dao.GetTotalOfProjects(projectName, 1)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get total of projects: %v", err)
|
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
|
||||||
}
|
|
||||||
projectList, err = dao.GetProjects(projectName, 1, pageSize, pageSize*(page-1))
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get projects: %v", err)
|
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//if the request is not for public projects, user must login or provide credential
|
//if the request is not for public projects, user must login or provide credential
|
||||||
p.userID = p.ValidateUser()
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
isAdmin, err = dao.IsAdminRole(p.userID)
|
p.HandleUnauthorized()
|
||||||
if err != nil {
|
return
|
||||||
log.Errorf("Error occured in check admin, error: %v", err)
|
|
||||||
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
|
||||||
}
|
}
|
||||||
if isAdmin {
|
|
||||||
total, err = dao.GetTotalOfProjects(projectName)
|
if !p.SecurityCtx.IsSysAdmin() {
|
||||||
if err != nil {
|
query.Member = &models.Member{
|
||||||
log.Errorf("failed to get total of projects: %v", err)
|
Name: p.SecurityCtx.GetUsername(),
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
|
||||||
}
|
|
||||||
projectList, err = dao.GetProjects(projectName, pageSize, pageSize*(page-1))
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get projects: %v", err)
|
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
total, err = dao.GetTotalOfUserRelevantProjects(p.userID, projectName)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get total of projects: %v", err)
|
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
|
||||||
}
|
|
||||||
projectList, err = dao.GetUserRelevantProjects(p.userID, projectName, pageSize, pageSize*(page-1))
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get projects: %v", err)
|
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(projectList); i++ {
|
total, err := p.ProjectMgr.GetTotal(query)
|
||||||
if public != 1 {
|
if err != nil {
|
||||||
roles, err := dao.GetUserProjectRoles(p.userID, projectList[i].ProjectID)
|
p.HandleInternalServerError(fmt.Sprintf("failed to get total of projects: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
page, size := p.GetPaginationParams()
|
||||||
|
query.Pagination = &models.Pagination{
|
||||||
|
Page: page,
|
||||||
|
Size: size,
|
||||||
|
}
|
||||||
|
|
||||||
|
projects, err := p.ProjectMgr.GetAll(query)
|
||||||
|
if err != nil {
|
||||||
|
p.HandleInternalServerError(fmt.Sprintf("failed to get projects: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, project := range projects {
|
||||||
|
if query.Public == nil || *query.Public == false {
|
||||||
|
roles, err := p.ProjectMgr.GetRoles(p.SecurityCtx.GetUsername(), project.ProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get user's project role: %v", err)
|
p.HandleInternalServerError(fmt.Sprintf("failed to get roles of user %s to project %d: %v",
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
p.SecurityCtx.GetUsername(), project.ProjectID, err))
|
||||||
}
|
return
|
||||||
if len(roles) != 0 {
|
|
||||||
projectList[i].Role = roles[0].RoleID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectList[i].Role == models.PROJECTADMIN ||
|
if len(roles) != 0 {
|
||||||
isAdmin {
|
project.Role = roles[0]
|
||||||
projectList[i].Togglable = true
|
}
|
||||||
|
|
||||||
|
if project.Role == common.RoleProjectAdmin ||
|
||||||
|
p.SecurityCtx.IsSysAdmin() {
|
||||||
|
project.Togglable = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repos, err := dao.GetRepositoryByProjectName(projectList[i].Name)
|
repos, err := dao.GetRepositoryByProjectName(project.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get repositories of project %s: %v", projectList[i].Name, err)
|
log.Errorf("failed to get repositories of project %s: %v", project.Name, err)
|
||||||
p.CustomAbort(http.StatusInternalServerError, "")
|
p.CustomAbort(http.StatusInternalServerError, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
projectList[i].RepoCount = len(repos)
|
project.RepoCount = len(repos)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.SetPaginationHeader(total, page, pageSize)
|
p.SetPaginationHeader(total, page, size)
|
||||||
p.Data["json"] = projectList
|
p.Data["json"] = projects
|
||||||
p.ServeJSON()
|
p.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleProjectPublic ...
|
// ToggleProjectPublic ...
|
||||||
func (p *ProjectAPI) ToggleProjectPublic() {
|
func (p *ProjectAPI) ToggleProjectPublic() {
|
||||||
p.userID = p.ValidateUser()
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
|
p.HandleUnauthorized()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.SecurityCtx.HasAllPerm(p.project.ProjectID) {
|
||||||
|
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var req projectReq
|
var req projectReq
|
||||||
|
|
||||||
projectID, err := strconv.ParseInt(p.Ctx.Input.Param(":id"), 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error parsing project id: %d, error: %v", projectID, err)
|
|
||||||
p.RenderError(http.StatusBadRequest, "invalid project id")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
p.DecodeJSONReq(&req)
|
p.DecodeJSONReq(&req)
|
||||||
public := req.Public
|
if req.Public != 0 && req.Public != 1 {
|
||||||
if !isProjectAdmin(p.userID, projectID) {
|
p.HandleBadRequest("public should be 0 or 1")
|
||||||
log.Warningf("Current user, id: %d does not have project admin role for project, id: %d", p.userID, projectID)
|
|
||||||
p.RenderError(http.StatusForbidden, "")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = dao.ToggleProjectPublicity(p.projectID, public)
|
|
||||||
if err != nil {
|
if err := p.ProjectMgr.Update(p.project.ProjectID,
|
||||||
log.Errorf("Error while updating project, project id: %d, error: %v", projectID, err)
|
&models.Project{
|
||||||
p.RenderError(http.StatusInternalServerError, "Failed to update project")
|
Public: req.Public,
|
||||||
|
}); err != nil {
|
||||||
|
p.HandleInternalServerError(fmt.Sprintf("failed to update project %d: %v",
|
||||||
|
p.project.ProjectID, err))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterAccessLog handles GET to /api/projects/{}/logs
|
// FilterAccessLog handles GET to /api/projects/{}/logs
|
||||||
func (p *ProjectAPI) FilterAccessLog() {
|
func (p *ProjectAPI) FilterAccessLog() {
|
||||||
p.userID = p.ValidateUser()
|
if !p.SecurityCtx.IsAuthenticated() {
|
||||||
|
p.HandleUnauthorized()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.SecurityCtx.HasReadPerm(p.project.ProjectID) {
|
||||||
|
p.HandleForbidden(p.SecurityCtx.GetUsername())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var query models.AccessLog
|
var query models.AccessLog
|
||||||
p.DecodeJSONReq(&query)
|
p.DecodeJSONReq(&query)
|
||||||
|
|
||||||
if !checkProjectPermission(p.userID, p.projectID) {
|
query.ProjectID = p.project.ProjectID
|
||||||
log.Warningf("Current user, user id: %d does not have permission to read accesslog of project, id: %d", p.userID, p.projectID)
|
|
||||||
p.RenderError(http.StatusForbidden, "")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
query.ProjectID = p.projectID
|
|
||||||
query.BeginTime = time.Unix(query.BeginTimestamp, 0)
|
query.BeginTime = time.Unix(query.BeginTimestamp, 0)
|
||||||
query.EndTime = time.Unix(query.EndTimestamp, 0)
|
query.EndTime = time.Unix(query.EndTimestamp, 0)
|
||||||
|
|
||||||
@ -422,34 +407,7 @@ func (p *ProjectAPI) FilterAccessLog() {
|
|||||||
p.ServeJSON()
|
p.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func isProjectAdmin(userID int, pid int64) bool {
|
// TODO move this to package models
|
||||||
isSysAdmin, err := dao.IsAdminRole(userID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in IsAdminRole, returning false, error: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if isSysAdmin {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
rolelist, err := dao.GetUserProjectRoles(userID, pid)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in GetUserProjectRoles, returning false, error: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
hasProjectAdminRole := false
|
|
||||||
for _, role := range rolelist {
|
|
||||||
if role.RoleID == models.PROJECTADMIN {
|
|
||||||
hasProjectAdminRole = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasProjectAdminRole
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateProjectReq(req projectReq) error {
|
func validateProjectReq(req projectReq) error {
|
||||||
pn := req.ProjectName
|
pn := req.ProjectName
|
||||||
if isIllegalLength(req.ProjectName, projectNameMinLen, projectNameMaxLen) {
|
if isIllegalLength(req.ProjectName, projectNameMinLen, projectNameMaxLen) {
|
||||||
|
@ -15,11 +15,12 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/vmware/harbor/tests/apitests/apilib"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/vmware/harbor/tests/apitests/apilib"
|
||||||
)
|
)
|
||||||
|
|
||||||
var addProject *apilib.ProjectReq
|
var addProject *apilib.ProjectReq
|
||||||
@ -264,18 +265,8 @@ func TestProHead(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
|
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
|
||||||
}
|
}
|
||||||
//----------------------------case 3 : Response Code=401:User need to log in first..----------------------------//
|
|
||||||
fmt.Println("case 3: respose code:401,User need to log in first..")
|
|
||||||
httpStatusCode, err = apiTest.ProjectsHead(*unknownUsr, "libra")
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error while search project by proName", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 401")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToggleProjectPublicity(t *testing.T) {
|
func TestToggleProjectPublicity(t *testing.T) {
|
||||||
@ -313,7 +304,7 @@ func TestToggleProjectPublicity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
//-------------------case4: Response Code=404 Not found the project------------------------------//
|
//-------------------case4: Response Code=404 Not found the project------------------------------//
|
||||||
fmt.Println("case 4: respose code:404, Not found the project")
|
fmt.Println("case 4: respose code:404, Not found the project")
|
||||||
httpStatusCode, err = apiTest.ToggleProjectPublicity(*admin, "0", 1)
|
httpStatusCode, err = apiTest.ToggleProjectPublicity(*admin, "1234", 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error while search project by proId", err.Error())
|
t.Error("Error while search project by proId", err.Error())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
|
@ -69,7 +69,14 @@ func (ra *RepositoryAPI) Get() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ra.ProjectMgr.Exist(projectID) {
|
exist, err := ra.ProjectMgr.Exist(projectID)
|
||||||
|
if err != nil {
|
||||||
|
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %d: %v",
|
||||||
|
projectID, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
ra.HandleNotFound(fmt.Sprintf("project %d not found", projectID))
|
ra.HandleNotFound(fmt.Sprintf("project %d not found", projectID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -146,7 +153,14 @@ func (ra *RepositoryAPI) Delete() {
|
|||||||
repoName := ra.GetString(":splat")
|
repoName := ra.GetString(":splat")
|
||||||
|
|
||||||
projectName, _ := utils.ParseRepository(repoName)
|
projectName, _ := utils.ParseRepository(repoName)
|
||||||
if !ra.ProjectMgr.Exist(projectName) {
|
exist, err := ra.ProjectMgr.Exist(projectName)
|
||||||
|
if err != nil {
|
||||||
|
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
|
||||||
|
projectName, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
ra.HandleNotFound(fmt.Sprintf("project %s not found", projectName))
|
ra.HandleNotFound(fmt.Sprintf("project %s not found", projectName))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -236,7 +250,18 @@ func (ra *RepositoryAPI) Delete() {
|
|||||||
go TriggerReplicationByRepository(repoName, []string{t}, models.RepOpDelete)
|
go TriggerReplicationByRepository(repoName, []string{t}, models.RepOpDelete)
|
||||||
|
|
||||||
go func(tag string) {
|
go func(tag string) {
|
||||||
project := ra.ProjectMgr.Get(projectName)
|
project, err := ra.ProjectMgr.Get(projectName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get the project %s: %v",
|
||||||
|
projectName, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if project == nil {
|
||||||
|
log.Error("project %s not found", projectName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := dao.AddAccessLog(models.AccessLog{
|
if err := dao.AddAccessLog(models.AccessLog{
|
||||||
Username: ra.SecurityCtx.GetUsername(),
|
Username: ra.SecurityCtx.GetUsername(),
|
||||||
ProjectID: project.ProjectID,
|
ProjectID: project.ProjectID,
|
||||||
@ -250,7 +275,7 @@ func (ra *RepositoryAPI) Delete() {
|
|||||||
}(t)
|
}(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
exist, err := repositoryExist(repoName, rc)
|
exist, err = repositoryExist(repoName, rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to check the existence of repository %s: %v", repoName, err)
|
log.Errorf("failed to check the existence of repository %s: %v", repoName, err)
|
||||||
ra.CustomAbort(http.StatusInternalServerError, "")
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
@ -268,7 +293,14 @@ func (ra *RepositoryAPI) GetTags() {
|
|||||||
repoName := ra.GetString(":splat")
|
repoName := ra.GetString(":splat")
|
||||||
|
|
||||||
projectName, _ := utils.ParseRepository(repoName)
|
projectName, _ := utils.ParseRepository(repoName)
|
||||||
if !ra.ProjectMgr.Exist(projectName) {
|
exist, err := ra.ProjectMgr.Exist(projectName)
|
||||||
|
if err != nil {
|
||||||
|
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
|
||||||
|
projectName, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
ra.HandleNotFound(fmt.Sprintf("project %s not found", projectName))
|
ra.HandleNotFound(fmt.Sprintf("project %s not found", projectName))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -360,7 +392,14 @@ func (ra *RepositoryAPI) GetManifests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
projectName, _ := utils.ParseRepository(repoName)
|
projectName, _ := utils.ParseRepository(repoName)
|
||||||
if !ra.ProjectMgr.Exist(projectName) {
|
exist, err := ra.ProjectMgr.Exist(projectName)
|
||||||
|
if err != nil {
|
||||||
|
ra.HandleInternalServerError(fmt.Sprintf("failed to check the existence of project %s: %v",
|
||||||
|
projectName, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
ra.HandleNotFound(fmt.Sprintf("project %s not found", projectName))
|
ra.HandleNotFound(fmt.Sprintf("project %s not found", projectName))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -455,10 +494,19 @@ func (ra *RepositoryAPI) GetTopRepos() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
projectIDs := []int64{}
|
projectIDs := []int64{}
|
||||||
projects := ra.ProjectMgr.GetPublic()
|
projects, err := ra.ProjectMgr.GetPublic()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get the public projects: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
if ra.SecurityCtx.IsAuthenticated() {
|
if ra.SecurityCtx.IsAuthenticated() {
|
||||||
projects = append(projects, ra.ProjectMgr.GetByMember(
|
list, err := ra.ProjectMgr.GetByMember(ra.SecurityCtx.GetUsername())
|
||||||
ra.SecurityCtx.GetUsername())...)
|
if err != nil {
|
||||||
|
log.Errorf("failed to get projects which the user %s is a member of: %v",
|
||||||
|
ra.SecurityCtx.GetUsername(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
projects = append(projects, list...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, project := range projects {
|
for _, project := range projects {
|
||||||
|
@ -33,7 +33,7 @@ type SearchAPI struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type searchResult struct {
|
type searchResult struct {
|
||||||
Project []models.Project `json:"project"`
|
Project []*models.Project `json:"project"`
|
||||||
Repository []map[string]interface{} `json:"repository"`
|
Repository []map[string]interface{} `json:"repository"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +52,10 @@ func (s *SearchAPI) Get() {
|
|||||||
s.CustomAbort(http.StatusInternalServerError, "internal error")
|
s.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
var projects []models.Project
|
var projects []*models.Project
|
||||||
|
|
||||||
if isSysAdmin {
|
if isSysAdmin {
|
||||||
projects, err = dao.GetProjects("")
|
projects, err = dao.GetProjects(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get all projects: %v", err)
|
log.Errorf("failed to get all projects: %v", err)
|
||||||
s.CustomAbort(http.StatusInternalServerError, "internal error")
|
s.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||||
@ -70,7 +70,7 @@ func (s *SearchAPI) Get() {
|
|||||||
|
|
||||||
projectSorter := &models.ProjectSorter{Projects: projects}
|
projectSorter := &models.ProjectSorter{Projects: projects}
|
||||||
sort.Sort(projectSorter)
|
sort.Sort(projectSorter)
|
||||||
projectResult := []models.Project{}
|
projectResult := []*models.Project{}
|
||||||
for _, p := range projects {
|
for _, p := range projects {
|
||||||
if len(keyword) > 0 && !strings.Contains(p.Name, keyword) {
|
if len(keyword) > 0 && !strings.Contains(p.Name, keyword) {
|
||||||
continue
|
continue
|
||||||
@ -113,7 +113,7 @@ func (s *SearchAPI) Get() {
|
|||||||
s.ServeJSON()
|
s.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterRepositories(projects []models.Project, keyword string) (
|
func filterRepositories(projects []*models.Project, keyword string) (
|
||||||
[]map[string]interface{}, error) {
|
[]map[string]interface{}, error) {
|
||||||
|
|
||||||
repositories, err := dao.GetAllRepositories()
|
repositories, err := dao.GetAllRepositories()
|
||||||
|
@ -17,9 +17,10 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/src/common/api"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
"github.com/vmware/harbor/src/common/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -51,8 +52,10 @@ func (s *StatisticAPI) Prepare() {
|
|||||||
// Get total projects and repos of the user
|
// Get total projects and repos of the user
|
||||||
func (s *StatisticAPI) Get() {
|
func (s *StatisticAPI) Get() {
|
||||||
statistic := map[string]int64{}
|
statistic := map[string]int64{}
|
||||||
|
t := true
|
||||||
n, err := dao.GetTotalOfProjects("", 1)
|
n, err := dao.GetTotalOfProjects(&models.QueryParam{
|
||||||
|
Public: &t,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get total of public projects: %v", err)
|
log.Errorf("failed to get total of public projects: %v", err)
|
||||||
s.CustomAbort(http.StatusInternalServerError, "")
|
s.CustomAbort(http.StatusInternalServerError, "")
|
||||||
@ -73,7 +76,7 @@ func (s *StatisticAPI) Get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isAdmin {
|
if isAdmin {
|
||||||
n, err := dao.GetTotalOfProjects("")
|
n, err := dao.GetTotalOfProjects(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get total of projects: %v", err)
|
log.Errorf("failed to get total of projects: %v", err)
|
||||||
s.CustomAbort(http.StatusInternalServerError, "")
|
s.CustomAbort(http.StatusInternalServerError, "")
|
||||||
@ -89,7 +92,18 @@ func (s *StatisticAPI) Get() {
|
|||||||
statistic[MRC] = n
|
statistic[MRC] = n
|
||||||
statistic[TRC] = n
|
statistic[TRC] = n
|
||||||
} else {
|
} else {
|
||||||
n, err := dao.GetTotalOfUserRelevantProjects(s.userID, "")
|
user, err := dao.GetUser(models.User{
|
||||||
|
UserID: s.userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get user %d: %v", s.userID, err)
|
||||||
|
s.CustomAbort(http.StatusInternalServerError, "")
|
||||||
|
}
|
||||||
|
n, err := dao.GetTotalOfProjects(&models.QueryParam{
|
||||||
|
Member: &models.Member{
|
||||||
|
Name: user.Username,
|
||||||
|
},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get total of projects for user %d: %v", s.userID, err)
|
log.Errorf("failed to get total of projects for user %d: %v", s.userID, err)
|
||||||
s.CustomAbort(http.StatusInternalServerError, "")
|
s.CustomAbort(http.StatusInternalServerError, "")
|
||||||
|
@ -15,80 +15,79 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProjectManager implements pm.PM interface based on database
|
// ProjectManager implements pm.PM interface based on database
|
||||||
type ProjectManager struct{}
|
type ProjectManager struct{}
|
||||||
|
|
||||||
// Get ...
|
// Get ...
|
||||||
func (p *ProjectManager) Get(projectIDOrName interface{}) *models.Project {
|
func (p *ProjectManager) Get(projectIDOrName interface{}) (
|
||||||
|
*models.Project, error) {
|
||||||
switch projectIDOrName.(type) {
|
switch projectIDOrName.(type) {
|
||||||
case string:
|
case string:
|
||||||
name := projectIDOrName.(string)
|
return dao.GetProjectByName(projectIDOrName.(string))
|
||||||
project, err := dao.GetProjectByName(name)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get project %s: %v", name, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return project
|
|
||||||
case int64:
|
case int64:
|
||||||
id := projectIDOrName.(int64)
|
return dao.GetProjectByID(projectIDOrName.(int64))
|
||||||
project, err := dao.GetProjectByID(id)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get project %d: %v", id, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return project
|
|
||||||
default:
|
default:
|
||||||
log.Errorf("unsupported type of %v, must be string or int64", projectIDOrName)
|
return nil, fmt.Errorf("unsupported type of %v, must be string or int64", projectIDOrName)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exist ...
|
// Exist ...
|
||||||
func (p *ProjectManager) Exist(projectIDOrName interface{}) bool {
|
func (p *ProjectManager) Exist(projectIDOrName interface{}) (bool, error) {
|
||||||
return p.Get(projectIDOrName) != nil
|
project, err := p.Get(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return project != nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPublic returns whether the project is public or not
|
// IsPublic returns whether the project is public or not
|
||||||
func (p *ProjectManager) IsPublic(projectIDOrName interface{}) bool {
|
func (p *ProjectManager) IsPublic(projectIDOrName interface{}) (bool, error) {
|
||||||
project := p.Get(projectIDOrName)
|
project, err := p.Get(projectIDOrName)
|
||||||
if project == nil {
|
if err != nil {
|
||||||
return false
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return project.Public == 1
|
if project == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return project.Public == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRoles return a role list which contains the user's roles to the project
|
// GetRoles return a role list which contains the user's roles to the project
|
||||||
func (p *ProjectManager) GetRoles(username string, projectIDOrName interface{}) []int {
|
func (p *ProjectManager) GetRoles(username string, projectIDOrName interface{}) ([]int, error) {
|
||||||
roles := []int{}
|
roles := []int{}
|
||||||
|
|
||||||
user, err := dao.GetUser(models.User{
|
user, err := dao.GetUser(models.User{
|
||||||
Username: username,
|
Username: username,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get user %s: %v", username, err)
|
return nil, fmt.Errorf("failed to get user %s: %v",
|
||||||
return roles
|
username, err)
|
||||||
}
|
}
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return roles
|
return roles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
project := p.Get(projectIDOrName)
|
project, err := p.Get(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if project == nil {
|
if project == nil {
|
||||||
return roles
|
return roles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
roleList, err := dao.GetUserProjectRoles(user.UserID, project.ProjectID)
|
roleList, err := dao.GetUserProjectRoles(user.UserID, project.ProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get roles for user %d to project %d: %v",
|
return nil, err
|
||||||
user.UserID, project.ProjectID, err)
|
|
||||||
return roles
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range roleList {
|
for _, role := range roleList {
|
||||||
@ -102,34 +101,102 @@ func (p *ProjectManager) GetRoles(username string, projectIDOrName interface{})
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return roles
|
return roles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublic returns all public projects
|
// GetPublic returns all public projects
|
||||||
func (p *ProjectManager) GetPublic() []models.Project {
|
func (p *ProjectManager) GetPublic() ([]*models.Project, error) {
|
||||||
projects, err := dao.GetProjects("", 1)
|
t := true
|
||||||
if err != nil {
|
return p.GetAll(&models.QueryParam{
|
||||||
log.Errorf("failed to get all public projects: %v", err)
|
Public: &t,
|
||||||
return []models.Project{}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
return projects
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByMember returns all projects which the user is a member of
|
// GetByMember returns all projects which the user is a member of
|
||||||
func (p *ProjectManager) GetByMember(username string) []models.Project {
|
func (p *ProjectManager) GetByMember(username string) (
|
||||||
user, err := dao.GetUser(models.User{
|
[]*models.Project, error) {
|
||||||
Username: username,
|
return p.GetAll(&models.QueryParam{
|
||||||
|
Member: &models.Member{
|
||||||
|
Name: username,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
}
|
||||||
log.Errorf("failed to get user %s: %v", username, err)
|
|
||||||
return []models.Project{}
|
// Create ...
|
||||||
}
|
func (p *ProjectManager) Create(project *models.Project) (int64, error) {
|
||||||
projects, err := dao.GetUserRelevantProjects(user.UserID, "")
|
if project == nil {
|
||||||
if err != nil {
|
return 0, fmt.Errorf("project is nil")
|
||||||
log.Errorf("failed to get projects of %s: %v", username, err)
|
|
||||||
return []models.Project{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return projects
|
if len(project.Name) == 0 {
|
||||||
|
return 0, fmt.Errorf("project name is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if project.OwnerID == 0 {
|
||||||
|
if len(project.OwnerName) == 0 {
|
||||||
|
return 0, fmt.Errorf("owner ID and owner name are both nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := dao.GetUser(models.User{
|
||||||
|
Username: project.OwnerName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
return 0, fmt.Errorf("can not get owner whose name is %s", project.OwnerName)
|
||||||
|
}
|
||||||
|
project.OwnerID = user.UserID
|
||||||
|
}
|
||||||
|
|
||||||
|
t := time.Now()
|
||||||
|
pro := &models.Project{
|
||||||
|
Name: project.Name,
|
||||||
|
Public: project.Public,
|
||||||
|
OwnerID: project.OwnerID,
|
||||||
|
CreationTime: t,
|
||||||
|
UpdateTime: t,
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.AddProject(*pro)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete ...
|
||||||
|
func (p *ProjectManager) Delete(projectIDOrName interface{}) error {
|
||||||
|
id, ok := projectIDOrName.(int64)
|
||||||
|
if !ok {
|
||||||
|
project, err := p.Get(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id = project.ProjectID
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.DeleteProject(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ...
|
||||||
|
func (p *ProjectManager) Update(projectIDOrName interface{},
|
||||||
|
project *models.Project) error {
|
||||||
|
id, ok := projectIDOrName.(int64)
|
||||||
|
if !ok {
|
||||||
|
pro, err := p.Get(projectIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id = pro.ProjectID
|
||||||
|
}
|
||||||
|
return dao.ToggleProjectPublicity(id, project.Public)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll returns a project list according to the query parameters
|
||||||
|
func (p *ProjectManager) GetAll(query *models.QueryParam) (
|
||||||
|
[]*models.Project, error) {
|
||||||
|
return dao.GetProjects(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTotal returns the total count according to the query parameters
|
||||||
|
func (p *ProjectManager) GetTotal(query *models.QueryParam) (
|
||||||
|
int64, error) {
|
||||||
|
return dao.GetTotalOfProjects(query)
|
||||||
}
|
}
|
||||||
|
@ -74,62 +74,76 @@ func TestGet(t *testing.T) {
|
|||||||
pm := &ProjectManager{}
|
pm := &ProjectManager{}
|
||||||
|
|
||||||
// project name
|
// project name
|
||||||
project := pm.Get("library")
|
project, err := pm.Get("library")
|
||||||
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, project)
|
assert.NotNil(t, project)
|
||||||
assert.Equal(t, "library", project.Name)
|
assert.Equal(t, "library", project.Name)
|
||||||
|
|
||||||
// project ID
|
// project ID
|
||||||
project = pm.Get(int64(1))
|
project, err = pm.Get(int64(1))
|
||||||
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, project)
|
assert.NotNil(t, project)
|
||||||
assert.Equal(t, int64(1), project.ProjectID)
|
assert.Equal(t, int64(1), project.ProjectID)
|
||||||
|
|
||||||
// non-exist project
|
// non-exist project
|
||||||
project = pm.Get("non-exist-project")
|
project, err = pm.Get("non-exist-project")
|
||||||
|
assert.Nil(t, err)
|
||||||
assert.Nil(t, project)
|
assert.Nil(t, project)
|
||||||
|
|
||||||
// invalid type
|
// invalid type
|
||||||
project = pm.Get(true)
|
project, err = pm.Get(true)
|
||||||
assert.Nil(t, project)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExist(t *testing.T) {
|
func TestExist(t *testing.T) {
|
||||||
pm := &ProjectManager{}
|
pm := &ProjectManager{}
|
||||||
|
|
||||||
// exist project
|
// exist project
|
||||||
assert.True(t, pm.Exist("library"))
|
exist, err := pm.Exist("library")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.True(t, exist)
|
||||||
|
|
||||||
// non-exist project
|
// non-exist project
|
||||||
assert.False(t, pm.Exist("non-exist-project"))
|
exist, err = pm.Exist("non-exist-project")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.False(t, exist)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsPublic(t *testing.T) {
|
func TestIsPublic(t *testing.T) {
|
||||||
pms := &ProjectManager{}
|
pms := &ProjectManager{}
|
||||||
// public project
|
// public project
|
||||||
assert.True(t, pms.IsPublic("library"))
|
public, err := pms.IsPublic("library")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.True(t, public)
|
||||||
// non exist project
|
// non exist project
|
||||||
assert.False(t, pms.IsPublic("non_exist_project"))
|
public, err = pms.IsPublic("non_exist_project")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.False(t, public)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRoles(t *testing.T) {
|
func TestGetRoles(t *testing.T) {
|
||||||
pm := &ProjectManager{}
|
pm := &ProjectManager{}
|
||||||
|
|
||||||
// non exist user
|
// non exist user
|
||||||
assert.Equal(t, []int{},
|
roles, err := pm.GetRoles("non_exist_user", int64(1))
|
||||||
pm.GetRoles("non_exist_user", int64(1)))
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, []int{}, roles)
|
||||||
|
|
||||||
// exist project
|
// exist project
|
||||||
assert.Equal(t, []int{common.RoleProjectAdmin},
|
roles, err = pm.GetRoles("admin", "library")
|
||||||
pm.GetRoles("admin", "library"))
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, []int{common.RoleProjectAdmin}, roles)
|
||||||
|
|
||||||
// non-exist project
|
// non-exist project
|
||||||
assert.Equal(t, []int{},
|
roles, err = pm.GetRoles("admin", "non_exist_project")
|
||||||
pm.GetRoles("admin", "non_exist_project"))
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, []int{}, roles)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPublic(t *testing.T) {
|
func TestGetPublic(t *testing.T) {
|
||||||
pm := &ProjectManager{}
|
pm := &ProjectManager{}
|
||||||
projects := pm.GetPublic()
|
projects, err := pm.GetPublic()
|
||||||
|
assert.Nil(t, err)
|
||||||
assert.NotEqual(t, 0, len(projects))
|
assert.NotEqual(t, 0, len(projects))
|
||||||
|
|
||||||
for _, project := range projects {
|
for _, project := range projects {
|
||||||
@ -139,6 +153,148 @@ func TestGetPublic(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetByMember(t *testing.T) {
|
func TestGetByMember(t *testing.T) {
|
||||||
pm := &ProjectManager{}
|
pm := &ProjectManager{}
|
||||||
projects := pm.GetByMember("admin")
|
projects, err := pm.GetByMember("admin")
|
||||||
|
assert.Nil(t, err)
|
||||||
assert.NotEqual(t, 0, len(projects))
|
assert.NotEqual(t, 0, len(projects))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateAndDelete(t *testing.T) {
|
||||||
|
pm := &ProjectManager{}
|
||||||
|
|
||||||
|
// nil project
|
||||||
|
_, err := pm.Create(nil)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
// nil project name
|
||||||
|
_, err = pm.Create(&models.Project{
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
// nil owner id and nil owner name
|
||||||
|
_, err = pm.Create(&models.Project{
|
||||||
|
Name: "test",
|
||||||
|
OwnerName: "non_exist_user",
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
// valid project, owner id
|
||||||
|
id, err := pm.Create(&models.Project{
|
||||||
|
Name: "test",
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Nil(t, pm.Delete(id))
|
||||||
|
|
||||||
|
// valid project, owner name
|
||||||
|
id, err = pm.Create(&models.Project{
|
||||||
|
Name: "test",
|
||||||
|
OwnerName: "admin",
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Nil(t, pm.Delete(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdate(t *testing.T) {
|
||||||
|
pm := &ProjectManager{}
|
||||||
|
|
||||||
|
id, err := pm.Create(&models.Project{
|
||||||
|
Name: "test",
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
defer pm.Delete(id)
|
||||||
|
|
||||||
|
project, err := pm.Get(id)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 0, project.Public)
|
||||||
|
|
||||||
|
project.Public = 1
|
||||||
|
assert.Nil(t, pm.Update(id, project))
|
||||||
|
|
||||||
|
project, err = pm.Get(id)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, project.Public)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTotal(t *testing.T) {
|
||||||
|
pm := &ProjectManager{}
|
||||||
|
|
||||||
|
id, err := pm.Create(&models.Project{
|
||||||
|
Name: "get_total_test",
|
||||||
|
OwnerID: 1,
|
||||||
|
Public: 1,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
defer pm.Delete(id)
|
||||||
|
|
||||||
|
// get by name
|
||||||
|
total, err := pm.GetTotal(&models.QueryParam{
|
||||||
|
Name: "get_total_test",
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, int64(1), total)
|
||||||
|
|
||||||
|
// get by owner
|
||||||
|
total, err = pm.GetTotal(&models.QueryParam{
|
||||||
|
Owner: "admin",
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotEqual(t, 0, total)
|
||||||
|
|
||||||
|
// get by public
|
||||||
|
value := true
|
||||||
|
total, err = pm.GetTotal(&models.QueryParam{
|
||||||
|
Public: &value,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotEqual(t, 0, total)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAll(t *testing.T) {
|
||||||
|
pm := &ProjectManager{}
|
||||||
|
|
||||||
|
id, err := pm.Create(&models.Project{
|
||||||
|
Name: "get_all_test",
|
||||||
|
OwnerID: 1,
|
||||||
|
Public: 1,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
defer pm.Delete(id)
|
||||||
|
|
||||||
|
// get by name
|
||||||
|
projects, err := pm.GetAll(&models.QueryParam{
|
||||||
|
Name: "get_all_test",
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, id, projects[0].ProjectID)
|
||||||
|
|
||||||
|
// get by owner
|
||||||
|
projects, err = pm.GetAll(&models.QueryParam{
|
||||||
|
Owner: "admin",
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
exist := false
|
||||||
|
for _, project := range projects {
|
||||||
|
if project.ProjectID == id {
|
||||||
|
exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, exist)
|
||||||
|
|
||||||
|
// get by public
|
||||||
|
value := true
|
||||||
|
projects, err = pm.GetAll(&models.QueryParam{
|
||||||
|
Public: &value,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
exist = false
|
||||||
|
for _, project := range projects {
|
||||||
|
if project.ProjectID == id {
|
||||||
|
exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, exist)
|
||||||
|
}
|
||||||
|
@ -21,12 +21,19 @@ import (
|
|||||||
// ProjectManager is the project mamager which abstracts the operations related
|
// ProjectManager is the project mamager which abstracts the operations related
|
||||||
// to projects
|
// to projects
|
||||||
type ProjectManager interface {
|
type ProjectManager interface {
|
||||||
Get(projectIDOrName interface{}) *models.Project
|
Get(projectIDOrName interface{}) (*models.Project, error)
|
||||||
IsPublic(projectIDOrName interface{}) bool
|
IsPublic(projectIDOrName interface{}) (bool, error)
|
||||||
Exist(projectIDOrName interface{}) bool
|
Exist(projectIDOrName interface{}) (bool, error)
|
||||||
GetRoles(username string, projectIDOrName interface{}) []int
|
GetRoles(username string, projectIDOrName interface{}) ([]int, error)
|
||||||
// get all public project
|
// get all public project
|
||||||
GetPublic() []models.Project
|
GetPublic() ([]*models.Project, error)
|
||||||
// get projects which the user is a member of
|
// get projects which the user is a member of
|
||||||
GetByMember(username string) []models.Project
|
GetByMember(username string) ([]*models.Project, error)
|
||||||
|
Create(*models.Project) (int64, error)
|
||||||
|
Delete(projectIDOrName interface{}) error
|
||||||
|
Update(projectIDOrName interface{}, project *models.Project) error
|
||||||
|
// GetAll returns a project list according to the query parameters
|
||||||
|
GetAll(query *models.QueryParam) ([]*models.Project, error)
|
||||||
|
// GetTotal returns the total count according to the query parameters
|
||||||
|
GetTotal(query *models.QueryParam) (int64, error)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user