mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
refactor GET /projects
This commit is contained in:
parent
42984fe1c9
commit
e97d7dab85
@ -43,21 +43,36 @@ paths:
|
||||
description: Unexpected internal errors.
|
||||
/projects:
|
||||
get:
|
||||
summary: Return projects created by Harbor
|
||||
summary: List projects
|
||||
description: |
|
||||
This endpoint returns all projects created by Harbor, and can be filtered by project name.
|
||||
parameters:
|
||||
- name: project_name
|
||||
- name: name
|
||||
in: query
|
||||
description: Project name for filtering results.
|
||||
description: The name of project.
|
||||
required: false
|
||||
type: string
|
||||
- name: is_public
|
||||
- name: public
|
||||
in: query
|
||||
description: Public sign for filtering projects.
|
||||
description: The project is public or private.
|
||||
required: false
|
||||
type: boolean
|
||||
format: int32
|
||||
- name: owner
|
||||
in: query
|
||||
description: The name of project owner.
|
||||
required: false
|
||||
type: string
|
||||
- name: member
|
||||
in: query
|
||||
description: The name of project member.
|
||||
required: false
|
||||
type: string
|
||||
- name: role
|
||||
in: query
|
||||
description: The role of member, only take effect when member is provided.
|
||||
required: false
|
||||
type: integer
|
||||
format: int32
|
||||
- name: page
|
||||
in: query
|
||||
type: integer
|
||||
|
@ -190,7 +190,7 @@ func GetHasReadPermProjects(username string) ([]*models.Project, error) {
|
||||
|
||||
// GetTotalOfProjects returns the total count of projects
|
||||
// according to the query conditions
|
||||
func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) {
|
||||
func GetTotalOfProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error) {
|
||||
|
||||
var (
|
||||
owner string
|
||||
@ -210,7 +210,7 @@ func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
sql, params := projectQueryConditions(owner, name, public, member, role)
|
||||
sql, params := projectQueryConditions(owner, name, public, member, role, base...)
|
||||
|
||||
sql = `select count(*) ` + sql
|
||||
|
||||
@ -220,7 +220,7 @@ func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) {
|
||||
}
|
||||
|
||||
// GetProjects returns a project list according to the query conditions
|
||||
func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
|
||||
func GetProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error) {
|
||||
|
||||
var (
|
||||
owner string
|
||||
@ -246,7 +246,7 @@ func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
|
||||
}
|
||||
}
|
||||
|
||||
sql, params := projectQueryConditions(owner, name, public, member, role)
|
||||
sql, params := projectQueryConditions(owner, name, public, member, role, base...)
|
||||
|
||||
sql = `select distinct p.project_id, p.name, p.public, p.owner_id,
|
||||
p.creation_time, p.update_time ` + sql
|
||||
@ -266,10 +266,37 @@ func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
|
||||
}
|
||||
|
||||
func projectQueryConditions(owner, name string, public *bool, member string,
|
||||
role int) (string, []interface{}) {
|
||||
role int, base ...*models.BaseProjectCollection) (string, []interface{}) {
|
||||
params := []interface{}{}
|
||||
|
||||
sql := ` from project p`
|
||||
// the base project collections:
|
||||
// 1. all projects
|
||||
// 2. public projects
|
||||
// 3. public projects and projects which the user is a member of
|
||||
// 4. projects which the user is a member of
|
||||
collection := `project `
|
||||
if len(base) != 0 && base[0] != nil {
|
||||
if len(base[0].Member) > 0 {
|
||||
collection = `(select pr.project_id, pr.owner_id, pr.name, pr.
|
||||
creation_time, pr.update_time, pr.deleted, pr.public
|
||||
from project pr
|
||||
join project_member prm
|
||||
on pr.project_id = prm.project_id
|
||||
join user ur
|
||||
on prm.user_id=ur.user_id
|
||||
where ur.username=? `
|
||||
if base[0].Public {
|
||||
collection += ` or pr.public=1 `
|
||||
}
|
||||
collection += `) `
|
||||
params = append(params, base[0].Member)
|
||||
} else if base[0].Public {
|
||||
collection = `(select * from project pr
|
||||
where pr.public=1) `
|
||||
}
|
||||
}
|
||||
|
||||
sql := ` from ` + collection + ` as p`
|
||||
|
||||
if len(owner) != 0 {
|
||||
sql += ` join user u1
|
||||
|
@ -88,3 +88,11 @@ type Pagination struct {
|
||||
Page int64
|
||||
Size int64
|
||||
}
|
||||
|
||||
// BaseProjectCollection contains the query conditions which can be used
|
||||
// to get a project collection. The collection can be used as the base to
|
||||
// do other filter
|
||||
type BaseProjectCollection struct {
|
||||
Public bool
|
||||
Member string
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ func (f *fakePM) Update(projectIDOrName interface{}, project *models.Project) er
|
||||
}
|
||||
|
||||
// nil implement
|
||||
func (f *fakePM) GetAll(*models.ProjectQueryParam) ([]*models.Project, error) {
|
||||
func (f *fakePM) GetAll(*models.ProjectQueryParam, ...*models.BaseProjectCollection) ([]*models.Project, error) {
|
||||
return []*models.Project{}, nil
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ func (f *fakePM) GetHasReadPerm(username ...string) ([]*models.Project, error) {
|
||||
}
|
||||
|
||||
// nil implement
|
||||
func (f *fakePM) GetTotal(*models.ProjectQueryParam) (int64, error) {
|
||||
func (f *fakePM) GetTotal(*models.ProjectQueryParam, ...*models.BaseProjectCollection) (int64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
|
@ -329,17 +329,10 @@ func (a testapi) ProjectsGetByPID(projectID string) (int, apilib.Project, error)
|
||||
}
|
||||
|
||||
//Search projects by projectName and isPublic
|
||||
func (a testapi) ProjectsGet(projectName string, isPublic int32, authInfo ...usrInfo) (int, []apilib.Project, error) {
|
||||
_sling := sling.New().Get(a.basePath)
|
||||
|
||||
//create api path
|
||||
path := "api/projects"
|
||||
_sling = _sling.Path(path)
|
||||
type QueryParams struct {
|
||||
ProjectName string `url:"project_name,omitempty"`
|
||||
IsPubilc int32 `url:"is_public,omitempty"`
|
||||
}
|
||||
_sling = _sling.QueryStruct(&QueryParams{ProjectName: projectName, IsPubilc: isPublic})
|
||||
func (a testapi) ProjectsGet(query *apilib.ProjectQuery, authInfo ...usrInfo) (int, []apilib.Project, error) {
|
||||
_sling := sling.New().Get(a.basePath).
|
||||
Path("api/projects").
|
||||
QueryStruct(query)
|
||||
|
||||
var successPayload []apilib.Project
|
||||
|
||||
@ -349,6 +342,7 @@ func (a testapi) ProjectsGet(projectName string, isPublic int32, authInfo ...usr
|
||||
if len(authInfo) > 0 {
|
||||
httpStatusCode, body, err = request(_sling, jsonAcceptHeader, authInfo[0])
|
||||
} else {
|
||||
log.Println("enter no auth $$$$$$$$$$$$$$$$$$$")
|
||||
httpStatusCode, body, err = request(_sling, jsonAcceptHeader)
|
||||
}
|
||||
|
||||
|
@ -23,28 +23,24 @@ import (
|
||||
)
|
||||
|
||||
func TestLogGet(t *testing.T) {
|
||||
|
||||
fmt.Println("Testing Log API")
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
assert := assert.New(t)
|
||||
|
||||
//prepare for test
|
||||
CommonAddUser()
|
||||
var project apilib.ProjectReq
|
||||
project.ProjectName = "my_project"
|
||||
project.Public = 1
|
||||
statusCode, result, err := apiTest.LogGet(*testUser)
|
||||
if err != nil {
|
||||
t.Error("Error while get log information", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(200), statusCode, "Log get should return 200")
|
||||
|
||||
}
|
||||
statusCode, result, err := apiTest.LogGet(*testUser)
|
||||
assert.Nil(err)
|
||||
assert.Equal(200, statusCode)
|
||||
|
||||
logNum := len(result)
|
||||
fmt.Println("result", result)
|
||||
//add the project first.
|
||||
|
||||
fmt.Println("add the project first.")
|
||||
project := apilib.ProjectReq{
|
||||
ProjectName: "project_for_test_log",
|
||||
Public: 1,
|
||||
}
|
||||
|
||||
reply, err := apiTest.ProjectsPost(*testUser, project)
|
||||
if err != nil {
|
||||
t.Error("Error while creat project", err.Error())
|
||||
@ -63,7 +59,7 @@ func TestLogGet(t *testing.T) {
|
||||
if num != 1 {
|
||||
assert.Equal(1, num, "add my_project log number should be 1")
|
||||
} else {
|
||||
assert.Equal("my_project/", result[index].RepoName, "RepoName should be equal")
|
||||
assert.Equal("project_for_test_log/", result[index].RepoName)
|
||||
assert.Equal("N/A", result[index].RepoTag, "RepoTag should be equal")
|
||||
assert.Equal("create", result[index].Operation, "Operation should be equal")
|
||||
}
|
||||
@ -73,7 +69,12 @@ func TestLogGet(t *testing.T) {
|
||||
//get the project
|
||||
var projects []apilib.Project
|
||||
var addProjectID int32
|
||||
httpStatusCode, projects, err := apiTest.ProjectsGet(project.ProjectName, 1)
|
||||
httpStatusCode, projects, err := apiTest.ProjectsGet(
|
||||
&apilib.ProjectQuery{
|
||||
Name: project.ProjectName,
|
||||
Owner: testUser.Name,
|
||||
Public: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Error("Error while search project by proName and isPublic", err.Error())
|
||||
t.Log(err)
|
||||
@ -81,6 +82,7 @@ func TestLogGet(t *testing.T) {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
addProjectID = projects[0].ProjectId
|
||||
}
|
||||
t.Logf("%%%%%%%%%%%%% %v", projects)
|
||||
|
||||
//delete the project
|
||||
projectID := strconv.Itoa(int(addProjectID))
|
||||
@ -99,7 +101,7 @@ func TestLogGet(t *testing.T) {
|
||||
func getLog(result []apilib.AccessLog) (int, int) {
|
||||
var num, index int
|
||||
for i := 0; i < len(result); i++ {
|
||||
if result[i].RepoName == "my_project/" {
|
||||
if result[i].RepoName == "project_for_test_log/" {
|
||||
num++
|
||||
index = i
|
||||
}
|
||||
|
@ -256,58 +256,81 @@ func projectContainsPolicy(id int64) (bool, error) {
|
||||
}
|
||||
|
||||
// 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() {
|
||||
query := &models.ProjectQueryParam{}
|
||||
// query strings
|
||||
page, size := p.GetPaginationParams()
|
||||
query := &models.ProjectQueryParam{
|
||||
Name: p.GetString("name"),
|
||||
Owner: p.GetString("owner"),
|
||||
Pagination: &models.Pagination{
|
||||
Page: page,
|
||||
Size: size,
|
||||
},
|
||||
}
|
||||
|
||||
query.Name = p.GetString("project_name")
|
||||
public := p.GetString("is_public")
|
||||
if len(public) != 0 {
|
||||
if public != "0" && public != "1" {
|
||||
p.HandleBadRequest("is_public should be 0 or 1")
|
||||
public := p.GetString("public")
|
||||
if len(public) > 0 {
|
||||
pub, err := strconv.ParseBool(public)
|
||||
if err != nil {
|
||||
p.HandleBadRequest(fmt.Sprintf("invalid public: %s", public))
|
||||
return
|
||||
}
|
||||
if public == "1" {
|
||||
t := true
|
||||
query.Public = &t
|
||||
query.Public = &pub
|
||||
}
|
||||
|
||||
member := p.GetString("member")
|
||||
if len(member) > 0 {
|
||||
query.Member = &models.Member{
|
||||
Name: member,
|
||||
}
|
||||
|
||||
role := p.GetString("role")
|
||||
if len(role) > 0 {
|
||||
r, err := strconv.Atoi(role)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
p.HandleBadRequest(fmt.Sprintf("invalid role: %s", role))
|
||||
return
|
||||
}
|
||||
}
|
||||
query.Member.Role = r
|
||||
}
|
||||
}
|
||||
|
||||
if query.Public == nil || *query.Public == false {
|
||||
//if the request is not for public projects, user must login or provide credential
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
// base project collection from which filter is done
|
||||
base := &models.BaseProjectCollection{}
|
||||
if !p.SecurityCtx.IsAuthenticated() {
|
||||
if query.Member != nil && len(query.Member.Name) > 0 {
|
||||
// must login if query member
|
||||
p.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
base.Public = true
|
||||
} else {
|
||||
if !p.SecurityCtx.IsSysAdmin() {
|
||||
query.Member = &models.Member{
|
||||
Name: p.SecurityCtx.GetUsername(),
|
||||
base.Member = p.SecurityCtx.GetUsername()
|
||||
if query.Member != nil && len(query.Member.Name) > 0 {
|
||||
base.Public = false
|
||||
} else {
|
||||
base.Public = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total, err := p.ProjectMgr.GetTotal(query)
|
||||
total, err := p.ProjectMgr.GetTotal(query, base)
|
||||
if err != nil {
|
||||
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)
|
||||
projects, err := p.ProjectMgr.GetAll(query, base)
|
||||
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 {
|
||||
if p.SecurityCtx.IsAuthenticated() {
|
||||
roles, err := p.ProjectMgr.GetRoles(p.SecurityCtx.GetUsername(), project.ProjectID)
|
||||
if err != nil {
|
||||
p.HandleInternalServerError(fmt.Sprintf("failed to get roles of user %s to project %d: %v",
|
||||
|
@ -90,8 +90,7 @@ func TestAddProject(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
//Get project by proName
|
||||
func TestProGetByName(t *testing.T) {
|
||||
func TestListProjects(t *testing.T) {
|
||||
fmt.Println("\nTest for Project GET API by project name")
|
||||
assert := assert.New(t)
|
||||
|
||||
@ -100,29 +99,39 @@ func TestProGetByName(t *testing.T) {
|
||||
|
||||
//----------------------------case 1 : Response Code=200----------------------------//
|
||||
fmt.Println("case 1: respose code:200")
|
||||
httpStatusCode, result, err := apiTest.ProjectsGet(addProject.ProjectName, 1)
|
||||
if err != nil {
|
||||
t.Error("Error while search project by proName and isPublic", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
||||
assert.Equal(int32(1), result[0].Public, "Public is wrong")
|
||||
//find add projectID
|
||||
addPID = int(result[0].ProjectId)
|
||||
}
|
||||
//----------------------------case 2 : Response Code=401:is_public=0----------------------------//
|
||||
fmt.Println("case 2: respose code:401,isPublic = 0")
|
||||
httpStatusCode, result, err = apiTest.ProjectsGet("library", 0)
|
||||
if err != nil {
|
||||
t.Error("Error while search project by proName and isPublic", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 200")
|
||||
}
|
||||
httpStatusCode, result, err := apiTest.ProjectsGet(
|
||||
&apilib.ProjectQuery{
|
||||
Name: addProject.ProjectName,
|
||||
Owner: admin.Name,
|
||||
Public: true,
|
||||
})
|
||||
assert.Nil(err)
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
|
||||
assert.Equal(int32(1), result[0].Public, "Public is wrong")
|
||||
|
||||
//find add projectID
|
||||
addPID = int(result[0].ProjectId)
|
||||
|
||||
//----------------------------case 2 : Response Code=401----------------------------//
|
||||
fmt.Println("case 2: respose code:401")
|
||||
httpStatusCode, result, err = apiTest.ProjectsGet(
|
||||
&apilib.ProjectQuery{
|
||||
Member: admin.Name,
|
||||
})
|
||||
t.Logf("$$$$$$$$$$$$$$$$$$$%v", result)
|
||||
assert.Nil(err)
|
||||
assert.Equal(int(401), httpStatusCode)
|
||||
|
||||
//-------------------case 3 : check admin project role------------------------//
|
||||
httpStatusCode, result, err = apiTest.ProjectsGet(addProject.ProjectName, 0, *admin)
|
||||
httpStatusCode, result, err = apiTest.ProjectsGet(
|
||||
&apilib.ProjectQuery{
|
||||
Name: addProject.ProjectName,
|
||||
Owner: admin.Name,
|
||||
Public: true,
|
||||
Member: admin.Name,
|
||||
Role: 1,
|
||||
}, *admin)
|
||||
if err != nil {
|
||||
t.Error("Error while search project by proName and isPublic", err.Error())
|
||||
t.Log(err)
|
||||
@ -144,7 +153,12 @@ func TestProGetByName(t *testing.T) {
|
||||
} else {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
}
|
||||
httpStatusCode, result, err = apiTest.ProjectsGet(addProject.ProjectName, 0, *testUser)
|
||||
httpStatusCode, result, err = apiTest.ProjectsGet(
|
||||
&apilib.ProjectQuery{
|
||||
Name: addProject.ProjectName,
|
||||
Member: TestUserName,
|
||||
Role: 2,
|
||||
}, *testUser)
|
||||
if err != nil {
|
||||
t.Error("Error while search project by proName and isPublic", err.Error())
|
||||
t.Log(err)
|
||||
|
@ -190,15 +190,15 @@ func (p *ProjectManager) Update(projectIDOrName interface{},
|
||||
}
|
||||
|
||||
// GetAll returns a project list according to the query parameters
|
||||
func (p *ProjectManager) GetAll(query *models.ProjectQueryParam) (
|
||||
func (p *ProjectManager) GetAll(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (
|
||||
[]*models.Project, error) {
|
||||
return dao.GetProjects(query)
|
||||
return dao.GetProjects(query, base...)
|
||||
}
|
||||
|
||||
// GetTotal returns the total count according to the query parameters
|
||||
func (p *ProjectManager) GetTotal(query *models.ProjectQueryParam) (
|
||||
func (p *ProjectManager) GetTotal(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (
|
||||
int64, error) {
|
||||
return dao.GetTotalOfProjects(query)
|
||||
return dao.GetTotalOfProjects(query, base...)
|
||||
}
|
||||
|
||||
// GetHasReadPerm returns projects which are public or the user is a member of
|
||||
|
@ -33,9 +33,9 @@ type ProjectManager interface {
|
||||
Delete(projectIDOrName interface{}) error
|
||||
Update(projectIDOrName interface{}, project *models.Project) error
|
||||
// GetAll returns a project list according to the query parameters
|
||||
GetAll(query *models.ProjectQueryParam) ([]*models.Project, error)
|
||||
GetAll(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error)
|
||||
// GetTotal returns the total count according to the query parameters
|
||||
GetTotal(query *models.ProjectQueryParam) (int64, error)
|
||||
GetTotal(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error)
|
||||
// GetHasReadPerm returns a project list which the user has read
|
||||
// permission of. The list should contains all public projects and
|
||||
// projects which the user is a member of if the username is not nil
|
||||
|
@ -57,3 +57,13 @@ type Project struct {
|
||||
// The number of the repositories under this project.
|
||||
RepoCount int32 `json:"repo_count,omitempty"`
|
||||
}
|
||||
|
||||
type ProjectQuery struct {
|
||||
Name string `json:"name"`
|
||||
Owner string `json:"owner"`
|
||||
Public bool `json:"public"`
|
||||
Member string `json:"member"`
|
||||
Role int `json:"role"`
|
||||
Page int64 `json:"page"`
|
||||
PageSize int64 `json:"page_size"`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user