Merge pull request #4419 from ywk253100/180314_filter_by_label

Implement filter repository and tags by label API
This commit is contained in:
Wenkai Yin 2018-03-21 11:22:06 +08:00 committed by GitHub
commit 8aa63b661c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 398 additions and 318 deletions

View File

@ -906,6 +906,11 @@ paths:
type: string
required: false
description: Repo name for filtering results.
- name: label_id
in: query
type: integer
required: false
description: The ID of label used to filter the result.
- name: page
in: query
type: integer
@ -1144,6 +1149,11 @@ paths:
type: string
required: true
description: Relevant repository name.
- name: label_ids
in: query
type: string
required: false
description: A list of comma separated label IDs.
tags:
- Products
responses:

View File

@ -277,8 +277,9 @@ create table harbor_resource_label (
label_id int NOT NULL,
# the resource_id is the ID of project when the resource_type is p
# the resource_id is the ID of repository when the resource_type is r
# the resource_id is the name of image when the resource_type is i
resource_id varchar(256) NOT NULL,
resource_id int,
# the resource_name is the name of image when the resource_type is i
resource_name varchar(256),
# 'p' for project
# 'r' for repository
# 'i' for image

View File

@ -267,9 +267,12 @@ create table harbor_resource_label (
/*
the resource_id is the ID of project when the resource_type is p
the resource_id is the ID of repository when the resource_type is r
the resource_id is the name of image when the resource_type is i
*/
resource_id varchar(256) NOT NULL,
resource_id int,
/*
the resource_name is the name of image when the resource_type is i
*/
resource_name varchar(256),
/*
'p' for project
'r' for repository

View File

@ -47,15 +47,6 @@ func GetRepositoryByName(name string) (*models.RepoRecord, error) {
return &r, err
}
// GetAllRepositories ...
func GetAllRepositories() ([]*models.RepoRecord, error) {
o := GetOrmer()
var repos []*models.RepoRecord
_, err := o.QueryTable("repository").Limit(-1).
OrderBy("Name").All(&repos)
return repos, err
}
// DeleteRepository ...
func DeleteRepository(name string) error {
o := GetOrmer()
@ -94,18 +85,6 @@ func RepositoryExists(name string) bool {
return o.QueryTable("repository").Filter("name", name).Exist()
}
// GetRepositoryByProjectName ...
func GetRepositoryByProjectName(name string) ([]*models.RepoRecord, error) {
sql := `select * from repository
where project_id = (
select project_id from project
where name = ?
)`
repos := []*models.RepoRecord{}
_, err := GetOrmer().Raw(sql, name).QueryRows(&repos)
return repos, err
}
//GetTopRepos returns the most popular repositories whose project ID is
// in projectIDs
func GetTopRepos(projectIDs []int64, n int) ([]*models.RepoRecord, error) {
@ -124,46 +103,78 @@ func GetTopRepos(projectIDs []int64, n int) ([]*models.RepoRecord, error) {
}
// GetTotalOfRepositories ...
func GetTotalOfRepositories(name string) (int64, error) {
qs := GetOrmer().QueryTable(&models.RepoRecord{})
if len(name) != 0 {
qs = qs.Filter("Name__contains", name)
func GetTotalOfRepositories(query ...*models.RepositoryQuery) (int64, error) {
sql, params := repositoryQueryConditions(query...)
sql = `select count(*) ` + sql
var total int64
if err := GetOrmer().Raw(sql, params).QueryRow(&total); err != nil {
return 0, err
}
return qs.Count()
return total, nil
}
// GetTotalOfRepositoriesByProject ...
func GetTotalOfRepositoriesByProject(projectIDs []int64, name string) (int64, error) {
if len(projectIDs) == 0 {
return 0, nil
}
qs := GetOrmer().QueryTable(&models.RepoRecord{}).
Filter("project_id__in", projectIDs)
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) {
// GetRepositories ...
func GetRepositories(query ...*models.RepositoryQuery) ([]*models.RepoRecord, error) {
repositories := []*models.RepoRecord{}
qs := GetOrmer().QueryTable(&models.RepoRecord{}).
Filter("ProjectID", projectID)
if len(name) != 0 {
qs = qs.Filter("Name__contains", name)
sql, params := repositoryQueryConditions(query...)
sql = `select r.repository_id, r.name, r.project_id, r.description, r.pull_count,
r.star_count, r.creation_time, r.update_time ` + sql + `order by r.name `
if len(query) > 0 && query[0] != nil {
page, size := query[0].Page, query[0].Size
if size > 0 {
sql += `limit ? `
params = append(params, size)
if page > 0 {
sql += `offset ? `
params = append(params, size*(page-1))
}
}
}
if limit > 0 {
qs = qs.Limit(limit).Offset(offset)
}
_, err := qs.All(&repositories)
return repositories, err
if _, err := GetOrmer().Raw(sql, params).QueryRows(&repositories); err != nil {
return nil, err
}
return repositories, nil
}
func repositoryQueryConditions(query ...*models.RepositoryQuery) (string, []interface{}) {
params := []interface{}{}
sql := `from repository r `
if len(query) == 0 || query[0] == nil {
return sql, params
}
q := query[0]
if len(q.ProjectName) > 0 {
sql += `join project p on r.project_id = p.project_id `
}
if q.LabelID > 0 {
sql += `join harbor_resource_label rl on r.repository_id = rl.resource_id
and rl.resource_type = 'r' `
}
sql += `where 1=1 `
if len(q.Name) > 0 {
sql += `and r.name = ? `
params = append(params, q.Name)
}
if len(q.ProjectIDs) > 0 {
sql += fmt.Sprintf(`and r.project_id in ( %s ) `,
paramPlaceholder(len(q.ProjectIDs)))
params = append(params, q.ProjectIDs)
}
if len(q.ProjectName) > 0 {
sql += `and p.name = ? `
params = append(params, q.ProjectName)
}
if q.LabelID > 0 {
sql += `and rl.label_id = ? `
params = append(params, q.LabelID)
}
return sql, params
}

View File

@ -16,10 +16,11 @@ package dao
import (
"fmt"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/models"
)
@ -32,61 +33,93 @@ var (
}
)
func TestGetRepositoryByProjectName(t *testing.T) {
if err := addRepository(repository); err != nil {
t.Fatalf("failed to add repository %s: %v", name, err)
}
defer func() {
if err := deleteRepository(name); err != nil {
t.Fatalf("failed to delete repository %s: %v", name, err)
}
}()
func TestGetTotalOfRepositories(t *testing.T) {
total, err := GetTotalOfRepositories()
require.Nil(t, err)
repositories, err := GetRepositoryByProjectName(project)
if err != nil {
t.Fatalf("failed to get repositories of project %s: %v",
project, err)
}
err = addRepository(repository)
require.Nil(t, err)
defer deleteRepository(name)
if len(repositories) == 0 {
t.Fatal("unexpected length of repositories: 0, at least 1")
}
n, err := GetTotalOfRepositories()
require.Nil(t, err)
assert.Equal(t, total+1, n)
}
exist := false
for _, repo := range repositories {
if repo.Name == name {
exist = true
func TestGetRepositories(t *testing.T) {
// no query
repositories, err := GetRepositories()
require.Nil(t, err)
n := len(repositories)
err = addRepository(repository)
require.Nil(t, err)
defer deleteRepository(name)
repositories, err = GetRepositories()
require.Nil(t, err)
assert.Equal(t, n+1, len(repositories))
// query by name
repositories, err = GetRepositories(&models.RepositoryQuery{
Name: name,
})
require.Nil(t, err)
require.Equal(t, 1, len(repositories))
assert.Equal(t, name, repositories[0].Name)
// query by project name
repositories, err = GetRepositories(&models.RepositoryQuery{
ProjectName: project,
})
require.Nil(t, err)
found := false
for _, repository := range repositories {
if repository.Name == name {
found = true
break
}
}
if !exist {
t.Errorf("there is no repository whose name is %s", name)
}
}
assert.True(t, found)
func TestGetTotalOfRepositories(t *testing.T) {
total, err := GetTotalOfRepositories("")
if err != nil {
t.Fatalf("failed to get total of repositoreis: %v", err)
}
if err := addRepository(repository); err != nil {
t.Fatalf("failed to add repository %s: %v", name, err)
}
defer func() {
if err := deleteRepository(name); err != nil {
t.Fatalf("failed to delete repository %s: %v", name, err)
// query by project ID
repositories, err = GetRepositories(&models.RepositoryQuery{
ProjectIDs: []int64{1},
})
require.Nil(t, err)
found = false
for _, repository := range repositories {
if repository.Name == name {
found = true
break
}
}()
n, err := GetTotalOfRepositories("")
if err != nil {
t.Fatalf("failed to get total of repositoreis: %v", err)
}
assert.True(t, found)
if n != total+1 {
t.Errorf("unexpected total: %d != %d", n, total+1)
}
// query by label ID
labelID, err := AddLabel(&models.Label{
Name: "label_for_test",
})
require.Nil(t, err)
defer DeleteLabel(labelID)
r, err := GetRepositoryByName(name)
require.Nil(t, err)
rlID, err := AddResourceLabel(&models.ResourceLabel{
LabelID: labelID,
ResourceID: r.RepositoryID,
ResourceType: common.ResourceTypeRepository,
})
require.Nil(t, err)
defer DeleteResourceLabel(rlID)
repositories, err = GetRepositories(&models.RepositoryQuery{
LabelID: labelID,
})
require.Nil(t, err)
require.Equal(t, 1, len(repositories))
assert.Equal(t, name, repositories[0].Name)
}
func TestGetTopRepos(t *testing.T) {
@ -149,112 +182,6 @@ func TestGetTopRepos(t *testing.T) {
require.Equal(topRepos[0].Name, repository3.Name)
}
func TestGetTotalOfRepositoriesByProject(t *testing.T) {
var projectID int64 = 1
repoName := "library/total_count"
total, err := GetTotalOfRepositoriesByProject([]int64{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,
ProjectID: projectID,
}); 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([]int64{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,
ProjectID: projectID,
}); 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 TestGetAllRepositories(t *testing.T) {
require := require.New(t)
var repos []*models.RepoRecord
repos, err := GetAllRepositories()
require.NoError(err)
allBefore := len(repos)
project1 := models.Project{
OwnerID: 1,
Name: "projectRepo",
}
var err2 error
project1.ProjectID, err2 = AddProject(project1)
require.NoError(err2)
for i := 0; i < 1200; i++ {
end := strconv.Itoa(i)
repoRecord := models.RepoRecord{
Name: "test" + end,
ProjectID: project1.ProjectID,
}
err := AddRepository(repoRecord)
require.NoError(err)
}
repos, err = GetAllRepositories()
require.NoError(err)
allAfter := len(repos)
require.Equal(allAfter, allBefore+1200)
err = clearRepositoryData()
require.NoError(err)
}
func addRepository(repository *models.RepoRecord) error {
return AddRepository(*repository)
}

View File

@ -29,14 +29,26 @@ func AddResourceLabel(rl *models.ResourceLabel) (int64, error) {
return GetOrmer().Insert(rl)
}
// GetResourceLabel specified by ID
func GetResourceLabel(rType, rID string, labelID int64) (*models.ResourceLabel, error) {
// GetResourceLabel specified by resource ID or name
// Get the ResourceLabel by ResourceID if rIDOrName is int
// Get the ResourceLabel by ResourceName if rIDOrName is string
func GetResourceLabel(rType string, rIDOrName interface{}, labelID int64) (*models.ResourceLabel, error) {
rl := &models.ResourceLabel{
ResourceType: rType,
ResourceID: rID,
LabelID: labelID,
}
if err := GetOrmer().Read(rl, "ResourceType", "ResourceID", "LabelID"); err != nil {
var err error
id, ok := rIDOrName.(int64)
if ok {
rl.ResourceID = id
err = GetOrmer().Read(rl, "ResourceType", "ResourceID", "LabelID")
} else {
rl.ResourceName = rIDOrName.(string)
err = GetOrmer().Read(rl, "ResourceType", "ResourceName", "LabelID")
}
if err != nil {
if err == orm.ErrNoRows {
return nil, nil
}
@ -47,13 +59,20 @@ func GetResourceLabel(rType, rID string, labelID int64) (*models.ResourceLabel,
}
// GetLabelsOfResource returns the label list of the resource
func GetLabelsOfResource(rType, rID string) ([]*models.Label, error) {
// Get the labels by ResourceID if rIDOrName is int, or get the labels by ResourceName
func GetLabelsOfResource(rType string, rIDOrName interface{}) ([]*models.Label, error) {
sql := `select l.id, l.name, l.description, l.color, l.scope, l.project_id, l.creation_time, l.update_time
from harbor_resource_label rl
join harbor_label l on rl.label_id=l.id
where rl.resource_type = ? and rl.resource_id = ?`
where rl.resource_type = ? and`
if _, ok := rIDOrName.(int64); ok {
sql += ` rl.resource_id = ?`
} else {
sql += ` rl.resource_name = ?`
}
labels := []*models.Label{}
_, err := GetOrmer().Raw(sql, rType, rID).QueryRows(&labels)
_, err := GetOrmer().Raw(sql, rType, rIDOrName).QueryRows(&labels)
return labels, err
}
@ -65,10 +84,39 @@ func DeleteResourceLabel(id int64) error {
return err
}
// DeleteLabelsOfResource removes all labels of resource specified by rType and rID
func DeleteLabelsOfResource(rType, rID string) error {
_, err := GetOrmer().QueryTable(&models.ResourceLabel{}).
Filter("ResourceType", rType).
Filter("ResourceID", rID).Delete()
// DeleteLabelsOfResource removes all labels of the resource
func DeleteLabelsOfResource(rType string, rIDOrName interface{}) error {
qs := GetOrmer().QueryTable(&models.ResourceLabel{}).
Filter("ResourceType", rType)
if _, ok := rIDOrName.(int64); ok {
qs = qs.Filter("ResourceID", rIDOrName)
} else {
qs = qs.Filter("ResourceName", rIDOrName)
}
_, err := qs.Delete()
return err
}
// ListResourceLabels lists ResourceLabel according to the query conditions
func ListResourceLabels(query ...*models.ResourceLabelQuery) ([]*models.ResourceLabel, error) {
qs := GetOrmer().QueryTable(&models.ResourceLabel{})
if len(query) > 0 {
q := query[0]
if q.LabelID > 0 {
qs = qs.Filter("LabelID", q.LabelID)
}
if len(q.ResourceType) > 0 {
qs = qs.Filter("ResourceType", q.ResourceType)
}
if q.ResourceID > 0 {
qs = qs.Filter("ResourceID", q.ResourceID)
}
if len(q.ResourceName) > 0 {
qs = qs.Filter("ResourceName", q.ResourceName)
}
}
rls := []*models.ResourceLabel{}
_, err := qs.All(&rls)
return rls, err
}

View File

@ -32,7 +32,7 @@ func TestMethodsOfResourceLabel(t *testing.T) {
require.Nil(t, err)
defer DeleteLabel(labelID)
resourceID := "1"
var resourceID int64 = 1
resourceType := common.ResourceTypeRepository
// add
@ -56,6 +56,16 @@ func TestMethodsOfResourceLabel(t *testing.T) {
require.Equal(t, 1, len(labels))
assert.Equal(t, id, r.ID)
// list
rls, err := ListResourceLabels(&models.ResourceLabelQuery{
LabelID: labelID,
ResourceType: resourceType,
ResourceID: resourceID,
})
require.Nil(t, err)
require.Equal(t, 1, len(rls))
assert.Equal(t, id, rls[0].ID)
// delete
err = DeleteResourceLabel(id)
require.Nil(t, err)

View File

@ -69,7 +69,8 @@ func (l *Label) Valid(v *validation.Validation) {
type ResourceLabel struct {
ID int64 `orm:"pk;auto;column(id)"`
LabelID int64 `orm:"column(label_id)"`
ResourceID string `orm:"column(resource_id)"`
ResourceID int64 `orm:"column(resource_id)"`
ResourceName string `orm:"column(resource_name)"`
ResourceType string `orm:"column(resource_type)"`
CreationTime time.Time `orm:"column(creation_time)"`
UpdateTime time.Time `orm:"column(update_time)"`
@ -79,3 +80,11 @@ type ResourceLabel struct {
func (r *ResourceLabel) TableName() string {
return "harbor_resource_label"
}
// ResourceLabelQuery : query parameters for the mapping relationships of resource and label
type ResourceLabelQuery struct {
LabelID int64
ResourceID int64
ResourceName string
ResourceType string
}

View File

@ -33,7 +33,7 @@ type Project struct {
OwnerName string `orm:"-" json:"owner_name"`
Togglable bool `orm:"-" json:"togglable"`
Role int `orm:"-" json:"current_user_role_id"`
RepoCount int `orm:"-" json:"repo_count"`
RepoCount int64 `orm:"-" json:"repo_count"`
Metadata map[string]string `orm:"-" json:"metadata"`
}

View File

@ -37,3 +37,12 @@ type RepoRecord struct {
func (rp *RepoRecord) TableName() string {
return RepoTable
}
// RepositoryQuery : query parameters for repository
type RepositoryQuery struct {
Name string
ProjectIDs []int64
ProjectName string
LabelID int64
Pagination
}

View File

@ -2,6 +2,7 @@ package registry
import (
"github.com/vmware/harbor/src/common/dao"
common_models "github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/replication"
"github.com/vmware/harbor/src/replication/models"
@ -30,7 +31,9 @@ func (ha *HarborAdaptor) GetNamespace(name string) models.Namespace {
//GetRepositories is used to get all the repositories under the specified namespace
func (ha *HarborAdaptor) GetRepositories(namespace string) []models.Repository {
repos, err := dao.GetRepositoryByProjectName(namespace)
repos, err := dao.GetRepositories(&common_models.RepositoryQuery{
ProjectName: namespace,
})
if err != nil {
log.Errorf("failed to get repositories under namespace %s: %v", namespace, err)
return nil

View File

@ -270,7 +270,9 @@ func (p *ProjectAPI) Deletable() {
}
func deletable(projectID int64) (*deletableResp, error) {
count, err := dao.GetTotalOfRepositoriesByProject([]int64{projectID}, "")
count, err := dao.GetTotalOfRepositories(&models.RepositoryQuery{
ProjectIDs: []int64{projectID},
})
if err != nil {
return nil, err
}
@ -395,13 +397,15 @@ func (p *ProjectAPI) populateProperties(project *models.Project) {
}
}
repos, err := dao.GetRepositoryByProjectName(project.Name)
total, err := dao.GetTotalOfRepositories(&models.RepositoryQuery{
ProjectIDs: []int64{project.ProjectID},
})
if err != nil {
log.Errorf("failed to get repositories of project %s: %v", project.Name, err)
log.Errorf("failed to get total of repositories of project %d: %v", project.ProjectID, err)
p.CustomAbort(http.StatusInternalServerError, "")
}
project.RepoCount = len(repos)
project.RepoCount = total
}
// Put ...

View File

@ -96,6 +96,12 @@ func (ra *RepositoryAPI) Get() {
return
}
labelID, err := ra.GetInt64("label_id", 0)
if err != nil {
ra.HandleBadRequest(fmt.Sprintf("invalid label_id: %s", ra.GetString("label_id")))
return
}
exist, err := ra.ProjectMgr.Exists(projectID)
if err != nil {
ra.ParseAndHandleError(fmt.Sprintf("failed to check the existence of project %d",
@ -117,33 +123,33 @@ func (ra *RepositoryAPI) Get() {
return
}
keyword := ra.GetString("q")
query := &models.RepositoryQuery{
ProjectIDs: []int64{projectID},
Name: ra.GetString("q"),
LabelID: labelID,
}
query.Page, query.Size = ra.GetPaginationParams()
total, err := dao.GetTotalOfRepositoriesByProject(
[]int64{projectID}, keyword)
total, err := dao.GetTotalOfRepositories(query)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to get total of repositories of project %d: %v",
projectID, err))
return
}
page, pageSize := ra.GetPaginationParams()
repositories, err := getRepositories(projectID,
keyword, pageSize, pageSize*(page-1))
repositories, err := getRepositories(query)
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to get repository: %v", err))
return
}
ra.SetPaginationHeader(total, page, pageSize)
ra.SetPaginationHeader(total, query.Page, query.Size)
ra.Data["json"] = repositories
ra.ServeJSON()
}
func getRepositories(projectID int64, keyword string,
limit, offset int64) ([]*repoResp, error) {
repositories, err := dao.GetRepositoriesByProject(projectID, keyword, limit, offset)
func getRepositories(query *models.RepositoryQuery) ([]*repoResp, error) {
repositories, err := dao.GetRepositories(query)
if err != nil {
return nil, err
}
@ -171,8 +177,7 @@ func assembleRepos(repositories []*models.RepoRecord) ([]*repoResp, error) {
}
repo.TagsCount = int64(len(tags))
labels, err := dao.GetLabelsOfResource(common.ResourceTypeRepository,
strconv.FormatInt(repository.RepositoryID, 10))
labels, err := dao.GetLabelsOfResource(common.ResourceTypeRepository, repository.RepositoryID)
if err != nil {
log.Errorf("failed to get labels of repository %s: %v", repository.Name, err)
} else {
@ -385,6 +390,11 @@ func (ra *RepositoryAPI) GetTag() {
// GetTags returns tags of a repository
func (ra *RepositoryAPI) GetTags() {
repoName := ra.GetString(":splat")
labelID, err := ra.GetInt64("label_id", 0)
if err != nil {
ra.HandleBadRequest(fmt.Sprintf("invalid label_id: %s", ra.GetString("label_id")))
return
}
projectName, _ := utils.ParseRepository(repoName)
exist, err := ra.ProjectMgr.Exists(projectName)
@ -420,7 +430,31 @@ func (ra *RepositoryAPI) GetTags() {
return
}
ra.Data["json"] = assembleTags(client, repoName, tags, ra.SecurityCtx.GetUsername())
// filter tags by label ID
if labelID > 0 {
rls, err := dao.ListResourceLabels(&models.ResourceLabelQuery{
LabelID: labelID,
ResourceType: common.ResourceTypeImage,
})
if err != nil {
ra.HandleInternalServerError(fmt.Sprintf("failed to list resource labels: %v", err))
return
}
labeledTags := map[string]struct{}{}
for _, rl := range rls {
labeledTags[strings.Split(rl.ResourceName, ":")[1]] = struct{}{}
}
ts := []string{}
for _, tag := range tags {
if _, ok := labeledTags[tag]; ok {
ts = append(ts, tag)
}
}
tags = ts
}
ra.Data["json"] = assembleTags(client, repoName, tags,
ra.SecurityCtx.GetUsername())
ra.ServeJSON()
}
@ -443,6 +477,15 @@ func assembleTags(client *registry.Repository, repository string,
for _, t := range tags {
item := &tagResp{}
// labels
image := fmt.Sprintf("%s:%s", repository, t)
labels, err := dao.GetLabelsOfResource(common.ResourceTypeImage, image)
if err != nil {
log.Errorf("failed to get labels of image %s: %v", image, err)
} else {
item.Labels = labels
}
// the detail information of tag
tagDetail, err := getTagDetail(client, t)
if err != nil {
@ -468,15 +511,6 @@ func assembleTags(client *registry.Repository, repository string,
}
}
// labels
image := fmt.Sprintf("%s:%s", repository, t)
labels, err := dao.GetLabelsOfResource(common.ResourceTypeImage, image)
if err != nil {
log.Errorf("failed to get labels of image %s: %v", image, err)
} else {
item.Labels = labels
}
result = append(result, item)
}

View File

@ -144,24 +144,20 @@ func (r *RepositoryLabelAPI) AddToImage() {
rl := &models.ResourceLabel{
LabelID: r.label.ID,
ResourceType: common.ResourceTypeImage,
ResourceID: fmt.Sprintf("%s:%s", r.repository.Name, r.tag),
ResourceName: fmt.Sprintf("%s:%s", r.repository.Name, r.tag),
}
r.addLabel(rl)
}
// RemoveFromImage removes the label from an image
func (r *RepositoryLabelAPI) RemoveFromImage() {
rl := &models.ResourceLabel{
LabelID: r.label.ID,
ResourceType: common.ResourceTypeImage,
ResourceID: fmt.Sprintf("%s:%s", r.repository.Name, r.tag),
}
r.removeLabel(rl)
r.removeLabel(common.ResourceTypeImage,
fmt.Sprintf("%s:%s", r.repository.Name, r.tag), r.label.ID)
}
// GetOfRepository returns labels of a repository
func (r *RepositoryLabelAPI) GetOfRepository() {
r.getLabels(common.ResourceTypeRepository, strconv.FormatInt(r.repository.RepositoryID, 10))
r.getLabels(common.ResourceTypeRepository, r.repository.RepositoryID)
}
// AddToRepository adds the label to a repository
@ -169,26 +165,21 @@ func (r *RepositoryLabelAPI) AddToRepository() {
rl := &models.ResourceLabel{
LabelID: r.label.ID,
ResourceType: common.ResourceTypeRepository,
ResourceID: strconv.FormatInt(r.repository.RepositoryID, 10),
ResourceID: r.repository.RepositoryID,
}
r.addLabel(rl)
}
// RemoveFromRepository removes the label from a repository
func (r *RepositoryLabelAPI) RemoveFromRepository() {
rl := &models.ResourceLabel{
LabelID: r.label.ID,
ResourceType: common.ResourceTypeRepository,
ResourceID: strconv.FormatInt(r.repository.RepositoryID, 10),
}
r.removeLabel(rl)
r.removeLabel(common.ResourceTypeRepository, r.repository.RepositoryID, r.label.ID)
}
func (r *RepositoryLabelAPI) getLabels(rType, rID string) {
labels, err := dao.GetLabelsOfResource(rType, rID)
func (r *RepositoryLabelAPI) getLabels(rType string, rIDOrName interface{}) {
labels, err := dao.GetLabelsOfResource(rType, rIDOrName)
if err != nil {
r.HandleInternalServerError(fmt.Sprintf("failed to get labels of resource %s %s: %v",
rType, rID, err))
r.HandleInternalServerError(fmt.Sprintf("failed to get labels of resource %s %v: %v",
rType, rIDOrName, err))
return
}
r.Data["json"] = labels
@ -196,10 +187,16 @@ func (r *RepositoryLabelAPI) getLabels(rType, rID string) {
}
func (r *RepositoryLabelAPI) addLabel(rl *models.ResourceLabel) {
rlabel, err := dao.GetResourceLabel(rl.ResourceType, rl.ResourceID, rl.LabelID)
var rIDOrName interface{}
if rl.ResourceID != 0 {
rIDOrName = rl.ResourceID
} else {
rIDOrName = rl.ResourceName
}
rlabel, err := dao.GetResourceLabel(rl.ResourceType, rIDOrName, rl.LabelID)
if err != nil {
r.HandleInternalServerError(fmt.Sprintf("failed to check the existence of label %d for resource %s %s: %v",
rl.LabelID, rl.ResourceType, rl.ResourceID, err))
r.HandleInternalServerError(fmt.Sprintf("failed to check the existence of label %d for resource %s %v: %v",
rl.LabelID, rl.ResourceType, rIDOrName, err))
return
}
@ -208,8 +205,8 @@ func (r *RepositoryLabelAPI) addLabel(rl *models.ResourceLabel) {
return
}
if _, err := dao.AddResourceLabel(rl); err != nil {
r.HandleInternalServerError(fmt.Sprintf("failed to add label %d to resource %s %s: %v",
rl.LabelID, rl.ResourceType, rl.ResourceID, err))
r.HandleInternalServerError(fmt.Sprintf("failed to add label %d to resource %s %v: %v",
rl.LabelID, rl.ResourceType, rIDOrName, err))
return
}
@ -217,22 +214,22 @@ func (r *RepositoryLabelAPI) addLabel(rl *models.ResourceLabel) {
r.Redirect(http.StatusOK, strconv.FormatInt(rl.LabelID, 10))
}
func (r *RepositoryLabelAPI) removeLabel(rl *models.ResourceLabel) {
rlabel, err := dao.GetResourceLabel(rl.ResourceType, rl.ResourceID, rl.LabelID)
func (r *RepositoryLabelAPI) removeLabel(rType string, rIDOrName interface{}, labelID int64) {
rl, err := dao.GetResourceLabel(rType, rIDOrName, labelID)
if err != nil {
r.HandleInternalServerError(fmt.Sprintf("failed to check the existence of label %d for resource %s %s: %v",
rl.LabelID, rl.ResourceType, rl.ResourceID, err))
r.HandleInternalServerError(fmt.Sprintf("failed to check the existence of label %d for resource %s %v: %v",
labelID, rType, rIDOrName, err))
return
}
if rlabel == nil {
if rl == nil {
r.HandleNotFound(fmt.Sprintf("label %d of resource %s %s not found",
rl.LabelID, rl.ResourceType, rl.ResourceID))
labelID, rType, rIDOrName))
return
}
if err = dao.DeleteResourceLabel(rlabel.ID); err != nil {
if err = dao.DeleteResourceLabel(rl.ID); err != nil {
r.HandleInternalServerError(fmt.Sprintf("failed to delete resource label record %d: %v",
rlabel.ID, err))
rl.ID, err))
return
}
}

View File

@ -27,7 +27,7 @@ func TestGetRepos(t *testing.T) {
assert := assert.New(t)
apiTest := newHarborAPI()
projectID := "1"
keyword := "hello-world"
keyword := "library/hello-world"
fmt.Println("Testing Repos Get API")
//-------------------case 1 : response code = 200------------------------//

View File

@ -99,13 +99,15 @@ func (s *SearchAPI) Get() {
}
}
repos, err := dao.GetRepositoryByProjectName(p.Name)
total, err := dao.GetTotalOfRepositories(&models.RepositoryQuery{
ProjectIDs: []int64{p.ProjectID},
})
if err != nil {
log.Errorf("failed to get repositories of project %s: %v", p.Name, err)
log.Errorf("failed to get total of repositories of project %d: %v", p.ProjectID, err)
s.CustomAbort(http.StatusInternalServerError, "")
}
p.RepoCount = len(repos)
p.RepoCount = total
projectResult = append(projectResult, p)
}
@ -124,7 +126,7 @@ func (s *SearchAPI) Get() {
func filterRepositories(projects []*models.Project, keyword string) (
[]map[string]interface{}, error) {
repositories, err := dao.GetAllRepositories()
repositories, err := dao.GetRepositories()
if err != nil {
return nil, err
}

View File

@ -64,17 +64,22 @@ func (s *StatisticAPI) Get() {
}
statistic[PubPC] = (int64)(len(pubProjs))
ids := []int64{}
for _, p := range pubProjs {
ids = append(ids, p.ProjectID)
if len(pubProjs) == 0 {
statistic[PubRC] = 0
} else {
ids := []int64{}
for _, p := range pubProjs {
ids = append(ids, p.ProjectID)
}
n, err := dao.GetTotalOfRepositories(&models.RepositoryQuery{
ProjectIDs: ids,
})
if err != nil {
log.Errorf("failed to get total of public repositories: %v", err)
s.CustomAbort(http.StatusInternalServerError, "")
}
statistic[PubRC] = n
}
n, err := dao.GetTotalOfRepositoriesByProject(ids, "")
if err != nil {
log.Errorf("failed to get total of public repositories: %v", err)
s.CustomAbort(http.StatusInternalServerError, "")
}
statistic[PubRC] = n
if s.SecurityCtx.IsSysAdmin() {
result, err := s.ProjectMgr.List(nil)
@ -85,7 +90,7 @@ func (s *StatisticAPI) Get() {
statistic[TPC] = result.Total
statistic[PriPC] = result.Total - statistic[PubPC]
n, err := dao.GetTotalOfRepositories("")
n, err := dao.GetTotalOfRepositories()
if err != nil {
log.Errorf("failed to get total of repositories: %v", err)
s.CustomAbort(http.StatusInternalServerError, "")
@ -107,20 +112,25 @@ func (s *StatisticAPI) Get() {
}
statistic[PriPC] = result.Total
if result.Total == 0 {
statistic[PriRC] = 0
} else {
ids := []int64{}
for _, p := range result.Projects {
ids = append(ids, p.ProjectID)
}
ids := []int64{}
for _, p := range result.Projects {
ids = append(ids, p.ProjectID)
n, err := dao.GetTotalOfRepositories(&models.RepositoryQuery{
ProjectIDs: ids,
})
if err != nil {
s.HandleInternalServerError(fmt.Sprintf(
"failed to get total of repositories for user %s: %v",
s.username, err))
return
}
statistic[PriRC] = n
}
n, err = dao.GetTotalOfRepositoriesByProject(ids, "")
if err != nil {
s.HandleInternalServerError(fmt.Sprintf(
"failed to get total of repositories for user %s: %v",
s.username, err))
return
}
statistic[PriRC] = n
}
s.Data["json"] = statistic

View File

@ -86,7 +86,7 @@ func SyncRegistry(pm promgr.ProjectManager) error {
}
var repoRecordsInDB []*models.RepoRecord
repoRecordsInDB, err = dao.GetAllRepositories()
repoRecordsInDB, err = dao.GetRepositories()
if err != nil {
log.Errorf("error occurred while getting all registories. %v", err)
return err

View File

@ -33,7 +33,7 @@ import (
// ScanAllImages scans all images of Harbor by submiting jobs to jobservice, the whole process will move on if failed to submit any job of a single image.
func ScanAllImages() error {
repos, err := dao.GetAllRepositories()
repos, err := dao.GetRepositories()
if err != nil {
log.Errorf("Failed to list all repositories, error: %v", err)
return err
@ -46,7 +46,9 @@ func ScanAllImages() error {
// ScanImagesByProjectID scans all images under a projet, the whole process will move on if failed to submit any job of a single image.
func ScanImagesByProjectID(id int64) error {
repos, err := dao.GetRepositoriesByProject(id, "", 0, 0)
repos, err := dao.GetRepositories(&models.RepositoryQuery{
ProjectIDs: []int64{id},
})
if err != nil {
log.Errorf("Failed list repositories in project %d, error: %v", id, err)
return err