mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-29 21:54:13 +01:00
Merge pull request #1536 from ywk253100/170307_repo_api
Refactor get repo API
This commit is contained in:
commit
282c7f61c4
@ -658,6 +658,11 @@ paths:
|
|||||||
format: int32
|
format: int32
|
||||||
required: true
|
required: true
|
||||||
description: Relevant project ID.
|
description: Relevant project ID.
|
||||||
|
- name: detail
|
||||||
|
in: query
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
description: Get detail info or not.
|
||||||
- name: q
|
- name: q
|
||||||
in: query
|
in: query
|
||||||
type: string
|
type: string
|
||||||
|
@ -184,3 +184,34 @@ func GetTotalOfUserRelevantRepositories(userID int, name string) (int64, error)
|
|||||||
err := GetOrmer().Raw(sql, params).QueryRow(&total)
|
err := GetOrmer().Raw(sql, params).QueryRow(&total)
|
||||||
return total, err
|
return total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTotalOfRepositoriesByProject ...
|
||||||
|
func GetTotalOfRepositoriesByProject(projectID int64, name string) (int64, error) {
|
||||||
|
qs := GetOrmer().QueryTable(&models.RepoRecord{}).
|
||||||
|
Filter("ProjectID", projectID)
|
||||||
|
|
||||||
|
if len(name) != 0 {
|
||||||
|
qs = qs.Filter("Name__contains", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return qs.Count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepositoriesByProject ...
|
||||||
|
func GetRepositoriesByProject(projectID int64, name string,
|
||||||
|
limit, offset int64) ([]*models.RepoRecord, error) {
|
||||||
|
|
||||||
|
repositories := []*models.RepoRecord{}
|
||||||
|
|
||||||
|
qs := GetOrmer().QueryTable(&models.RepoRecord{}).
|
||||||
|
Filter("ProjectID", projectID)
|
||||||
|
|
||||||
|
if len(name) != 0 {
|
||||||
|
qs = qs.Filter("Name__contains", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := qs.Limit(limit).
|
||||||
|
Offset(offset).All(&repositories)
|
||||||
|
|
||||||
|
return repositories, err
|
||||||
|
}
|
||||||
|
@ -340,6 +340,78 @@ func TestGetTopRepos(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetTotalOfRepositoriesByProject(t *testing.T) {
|
||||||
|
var projectID int64 = 1
|
||||||
|
repoName := "library/total_count"
|
||||||
|
|
||||||
|
total, err := GetTotalOfRepositoriesByProject(projectID, repoName)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to get total of repositoreis of project %d: %v", projectID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addRepository(&models.RepoRecord{
|
||||||
|
Name: repoName,
|
||||||
|
OwnerName: "admin",
|
||||||
|
ProjectName: "library",
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("failed to add repository %s: %v", repoName, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := deleteRepository(repoName); err != nil {
|
||||||
|
t.Errorf("failed to delete repository %s: %v", name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
n, err := GetTotalOfRepositoriesByProject(projectID, repoName)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to get total of repositoreis of project %d: %v", projectID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n != total+1 {
|
||||||
|
t.Errorf("unexpected total: %d != %d", n, total+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRepositoriesByProject(t *testing.T) {
|
||||||
|
var projectID int64 = 1
|
||||||
|
repoName := "library/repository"
|
||||||
|
|
||||||
|
if err := addRepository(&models.RepoRecord{
|
||||||
|
Name: repoName,
|
||||||
|
OwnerName: "admin",
|
||||||
|
ProjectName: "library",
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("failed to add repository %s: %v", repoName, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := deleteRepository(repoName); err != nil {
|
||||||
|
t.Errorf("failed to delete repository %s: %v", name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
repositories, err := GetRepositoriesByProject(projectID, repoName, 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to get repositoreis of project %d: %v", projectID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(repositories)
|
||||||
|
|
||||||
|
for _, repository := range repositories {
|
||||||
|
if repository.Name == repoName {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Errorf("repository %s not found", repoName)
|
||||||
|
}
|
||||||
|
|
||||||
func addRepository(repository *models.RepoRecord) error {
|
func addRepository(repository *models.RepoRecord) error {
|
||||||
return AddRepository(*repository)
|
return AddRepository(*repository)
|
||||||
}
|
}
|
||||||
|
@ -453,7 +453,7 @@ func (a testapi) PutProjectMember(authInfo usrInfo, projectID string, userID str
|
|||||||
|
|
||||||
//-------------------------Repositories Test---------------------------------------//
|
//-------------------------Repositories Test---------------------------------------//
|
||||||
//Return relevant repos of projectID
|
//Return relevant repos of projectID
|
||||||
func (a testapi) GetRepos(authInfo usrInfo, projectID string) (int, error) {
|
func (a testapi) GetRepos(authInfo usrInfo, projectID, detail string) (int, error) {
|
||||||
_sling := sling.New().Get(a.basePath)
|
_sling := sling.New().Get(a.basePath)
|
||||||
|
|
||||||
path := "/api/repositories/"
|
path := "/api/repositories/"
|
||||||
@ -462,9 +462,13 @@ func (a testapi) GetRepos(authInfo usrInfo, projectID string) (int, error) {
|
|||||||
|
|
||||||
type QueryParams struct {
|
type QueryParams struct {
|
||||||
ProjectID string `url:"project_id"`
|
ProjectID string `url:"project_id"`
|
||||||
|
Detail string `url:"detail"`
|
||||||
}
|
}
|
||||||
|
|
||||||
_sling = _sling.QueryStruct(&QueryParams{ProjectID: projectID})
|
_sling = _sling.QueryStruct(&QueryParams{
|
||||||
|
ProjectID: projectID,
|
||||||
|
Detail: detail,
|
||||||
|
})
|
||||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||||
return httpStatusCode, err
|
return httpStatusCode, err
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/manifest/schema2"
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
@ -44,6 +45,19 @@ type RepositoryAPI struct {
|
|||||||
api.BaseAPI
|
api.BaseAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type repoResp struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
OwnerID int64 `json:"owner_id"`
|
||||||
|
ProjectID int64 `json:"project_id"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
PullCount int64 `json:"pull_count"`
|
||||||
|
StarCount int64 `json:"star_count"`
|
||||||
|
TagsCount int64 `json:"tags_count"`
|
||||||
|
CreationTime time.Time `json:"creation_time"`
|
||||||
|
UpdateTime time.Time `json:"update_time"`
|
||||||
|
}
|
||||||
|
|
||||||
// Get ...
|
// Get ...
|
||||||
func (ra *RepositoryAPI) Get() {
|
func (ra *RepositoryAPI) Get() {
|
||||||
projectID, err := ra.GetInt64("project_id")
|
projectID, err := ra.GetInt64("project_id")
|
||||||
@ -51,8 +65,6 @@ func (ra *RepositoryAPI) Get() {
|
|||||||
ra.CustomAbort(http.StatusBadRequest, "invalid project_id")
|
ra.CustomAbort(http.StatusBadRequest, "invalid project_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
page, pageSize := ra.GetPaginationParams()
|
|
||||||
|
|
||||||
project, err := dao.GetProjectByID(projectID)
|
project, err := dao.GetProjectByID(projectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get project %d: %v", projectID, err)
|
log.Errorf("failed to get project %d: %v", projectID, err)
|
||||||
@ -77,30 +89,71 @@ func (ra *RepositoryAPI) Get() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories, err := getReposByProject(project.Name, ra.GetString("q"))
|
keyword := ra.GetString("q")
|
||||||
|
|
||||||
|
total, err := dao.GetTotalOfRepositoriesByProject(projectID, keyword)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get total of repositories of project %d: %v", projectID, err)
|
||||||
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
page, pageSize := ra.GetPaginationParams()
|
||||||
|
|
||||||
|
detail := ra.GetString("detail") == "1" || ra.GetString("detail") == "true"
|
||||||
|
|
||||||
|
repositories, err := getRepositories(projectID,
|
||||||
|
keyword, pageSize, pageSize*(page-1), detail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get repository: %v", err)
|
log.Errorf("failed to get repository: %v", err)
|
||||||
ra.CustomAbort(http.StatusInternalServerError, "")
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
total := int64(len(repositories))
|
|
||||||
|
|
||||||
if (page-1)*pageSize > total {
|
|
||||||
repositories = []string{}
|
|
||||||
} else {
|
|
||||||
repositories = repositories[(page-1)*pageSize:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if page*pageSize <= total {
|
|
||||||
repositories = repositories[:pageSize]
|
|
||||||
}
|
|
||||||
|
|
||||||
ra.SetPaginationHeader(total, page, pageSize)
|
ra.SetPaginationHeader(total, page, pageSize)
|
||||||
|
|
||||||
ra.Data["json"] = repositories
|
ra.Data["json"] = repositories
|
||||||
ra.ServeJSON()
|
ra.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRepositories(projectID int64, keyword string,
|
||||||
|
limit, offset int64, detail bool) (interface{}, error) {
|
||||||
|
repositories, err := dao.GetRepositoriesByProject(projectID, keyword, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//keep compatibility with old API
|
||||||
|
if !detail {
|
||||||
|
result := []string{}
|
||||||
|
for _, repository := range repositories {
|
||||||
|
result = append(result, repository.Name)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []*repoResp{}
|
||||||
|
for _, repository := range repositories {
|
||||||
|
repo := &repoResp{
|
||||||
|
ID: repository.RepositoryID,
|
||||||
|
Name: repository.Name,
|
||||||
|
OwnerID: repository.OwnerID,
|
||||||
|
ProjectID: repository.ProjectID,
|
||||||
|
Description: repository.Description,
|
||||||
|
PullCount: repository.PullCount,
|
||||||
|
StarCount: repository.StarCount,
|
||||||
|
CreationTime: repository.CreationTime,
|
||||||
|
UpdateTime: repository.UpdateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, err := getTags(repository.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
repo.TagsCount = int64(len(tags))
|
||||||
|
result = append(result, repo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Delete ...
|
// Delete ...
|
||||||
func (ra *RepositoryAPI) Delete() {
|
func (ra *RepositoryAPI) Delete() {
|
||||||
repoName := ra.GetString("repo_name")
|
repoName := ra.GetString("repo_name")
|
||||||
@ -119,11 +172,9 @@ func (ra *RepositoryAPI) Delete() {
|
|||||||
ra.CustomAbort(http.StatusNotFound, fmt.Sprintf("project %s not found", projectName))
|
ra.CustomAbort(http.StatusNotFound, fmt.Sprintf("project %s not found", projectName))
|
||||||
}
|
}
|
||||||
|
|
||||||
if project.Public == 0 {
|
userID := ra.ValidateUser()
|
||||||
userID := ra.ValidateUser()
|
if !hasProjectAdminRole(userID, project.ProjectID) {
|
||||||
if !hasProjectAdminRole(userID, project.ProjectID) {
|
ra.CustomAbort(http.StatusForbidden, "")
|
||||||
ra.CustomAbort(http.StatusForbidden, "")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, err := ra.initRepositoryClient(repoName)
|
rc, err := ra.initRepositoryClient(repoName)
|
||||||
|
@ -20,7 +20,7 @@ func TestGetRepos(t *testing.T) {
|
|||||||
fmt.Println("Testing Repos Get API")
|
fmt.Println("Testing Repos Get API")
|
||||||
//-------------------case 1 : response code = 200------------------------//
|
//-------------------case 1 : response code = 200------------------------//
|
||||||
fmt.Println("case 1 : response code = 200")
|
fmt.Println("case 1 : response code = 200")
|
||||||
httpStatusCode, err = apiTest.GetRepos(*admin, projectID)
|
httpStatusCode, err = apiTest.GetRepos(*admin, projectID, "true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error whihle get repos by projectID", err.Error())
|
t.Error("Error whihle get repos by projectID", err.Error())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@ -30,7 +30,7 @@ func TestGetRepos(t *testing.T) {
|
|||||||
//-------------------case 2 : response code = 400------------------------//
|
//-------------------case 2 : response code = 400------------------------//
|
||||||
fmt.Println("case 2 : response code = 409,invalid project_id")
|
fmt.Println("case 2 : response code = 409,invalid project_id")
|
||||||
projectID = "ccc"
|
projectID = "ccc"
|
||||||
httpStatusCode, err = apiTest.GetRepos(*admin, projectID)
|
httpStatusCode, err = apiTest.GetRepos(*admin, projectID, "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error whihle get repos by projectID", err.Error())
|
t.Error("Error whihle get repos by projectID", err.Error())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@ -40,7 +40,7 @@ func TestGetRepos(t *testing.T) {
|
|||||||
//-------------------case 3 : response code = 404------------------------//
|
//-------------------case 3 : response code = 404------------------------//
|
||||||
fmt.Println("case 3 : response code = 404:project not found")
|
fmt.Println("case 3 : response code = 404:project not found")
|
||||||
projectID = "111"
|
projectID = "111"
|
||||||
httpStatusCode, err = apiTest.GetRepos(*admin, projectID)
|
httpStatusCode, err = apiTest.GetRepos(*admin, projectID, "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error whihle get repos by projectID", err.Error())
|
t.Error("Error whihle get repos by projectID", err.Error())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
|
Loading…
Reference in New Issue
Block a user