mirror of
https://github.com/goharbor/harbor.git
synced 2024-10-05 00:37:32 +02:00
Merge branch 'master' into new-version-of-ui
This commit is contained in:
commit
07706fdafd
@ -113,23 +113,50 @@ func (p *ProjectAPI) Head() {
|
|||||||
|
|
||||||
// Get ...
|
// Get ...
|
||||||
func (p *ProjectAPI) Get() {
|
func (p *ProjectAPI) Get() {
|
||||||
queryProject := models.Project{UserID: p.userID}
|
var projectList []models.Project
|
||||||
projectName := p.GetString("project_name")
|
projectName := p.GetString("project_name")
|
||||||
if len(projectName) > 0 {
|
if len(projectName) > 0 {
|
||||||
queryProject.Name = "%" + projectName + "%"
|
projectName = "%" + projectName + "%"
|
||||||
|
}
|
||||||
|
var public int
|
||||||
|
var err error
|
||||||
|
isPublic := p.GetString("is_public")
|
||||||
|
if len(isPublic) > 0 {
|
||||||
|
public, err = strconv.Atoi(isPublic)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error parsing public property: %d, error: %v", isPublic, err)
|
||||||
|
p.CustomAbort(http.StatusBadRequest, "invalid project Id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isAdmin := false
|
||||||
|
if public == 1 {
|
||||||
|
projectList, err = dao.GetPublicProjects(projectName)
|
||||||
|
} else {
|
||||||
|
isAdmin, err = dao.IsAdminRole(p.userID)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error occured in check admin, error: %v", err)
|
||||||
|
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||||
|
}
|
||||||
|
if isAdmin {
|
||||||
|
projectList, err = dao.GetAllProjects(projectName)
|
||||||
|
} else {
|
||||||
|
projectList, err = dao.GetUserRelevantProjects(p.userID, projectName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public, _ := p.GetInt("is_public")
|
|
||||||
queryProject.Public = public
|
|
||||||
|
|
||||||
projectList, err := dao.QueryProject(queryProject)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error occurred in QueryProject, error: %v", err)
|
log.Errorf("Error occured in get projects info, error: %v", err)
|
||||||
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||||
}
|
}
|
||||||
for i := 0; i < len(projectList); i++ {
|
for i := 0; i < len(projectList); i++ {
|
||||||
if isProjectAdmin(p.userID, projectList[i].ProjectID) {
|
if public != 1 {
|
||||||
projectList[i].Togglable = true
|
if isAdmin {
|
||||||
|
projectList[i].Role = models.PROJECTADMIN
|
||||||
|
}
|
||||||
|
if projectList[i].Role == models.PROJECTADMIN {
|
||||||
|
projectList[i].Togglable = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
projectList[i].RepoCount = getRepoCountByProject(projectList[i].Name)
|
||||||
}
|
}
|
||||||
p.Data["json"] = projectList
|
p.Data["json"] = projectList
|
||||||
p.ServeJSON()
|
p.ServeJSON()
|
||||||
|
@ -55,13 +55,13 @@ func (s *SearchAPI) Get() {
|
|||||||
var projects []models.Project
|
var projects []models.Project
|
||||||
|
|
||||||
if isSysAdmin {
|
if isSysAdmin {
|
||||||
projects, err = dao.GetAllProjects()
|
projects, err = dao.GetAllProjects("")
|
||||||
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")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
projects, err = dao.GetUserRelevantProjects(userID)
|
projects, err = dao.SearchProjects(userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get user %d 's relevant projects: %v", userID, err)
|
log.Errorf("failed to get user %d 's relevant projects: %v", userID, err)
|
||||||
s.CustomAbort(http.StatusInternalServerError, "internal error")
|
s.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||||
|
117
api/statistic.go
Normal file
117
api/statistic.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/dao"
|
||||||
|
"github.com/vmware/harbor/models"
|
||||||
|
svc_utils "github.com/vmware/harbor/service/utils"
|
||||||
|
"github.com/vmware/harbor/utils/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StatisticAPI handles request to /api/statistics/
|
||||||
|
type StatisticAPI struct {
|
||||||
|
BaseAPI
|
||||||
|
userID int
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prepare validates the URL and the user
|
||||||
|
func (s *StatisticAPI) Prepare() {
|
||||||
|
s.userID = s.ValidateUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total projects and repos of the user
|
||||||
|
func (s *StatisticAPI) Get() {
|
||||||
|
isAdmin, err := dao.IsAdminRole(s.userID)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error occured in check admin, error: %v", err)
|
||||||
|
s.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||||
|
}
|
||||||
|
var projectList []models.Project
|
||||||
|
if isAdmin {
|
||||||
|
projectList, err = dao.GetAllProjects("")
|
||||||
|
} else {
|
||||||
|
projectList, err = dao.GetUserRelevantProjects(s.userID, "")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error occured in QueryProject, error: %v", err)
|
||||||
|
s.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||||
|
}
|
||||||
|
proMap := map[string]int{}
|
||||||
|
proMap["my_project_count"] = 0
|
||||||
|
proMap["my_repo_count"] = 0
|
||||||
|
proMap["public_project_count"] = 0
|
||||||
|
proMap["public_repo_count"] = 0
|
||||||
|
var publicProjects []models.Project
|
||||||
|
publicProjects, err = dao.GetPublicProjects("")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error occured in QueryPublicProject, error: %v", err)
|
||||||
|
s.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||||
|
}
|
||||||
|
proMap["public_project_count"] = len(publicProjects)
|
||||||
|
for i := 0; i < len(publicProjects); i++ {
|
||||||
|
proMap["public_repo_count"] += getRepoCountByProject(publicProjects[i].Name)
|
||||||
|
}
|
||||||
|
if isAdmin {
|
||||||
|
proMap["total_project_count"] = len(projectList)
|
||||||
|
proMap["total_repo_count"] = getTotalRepoCount()
|
||||||
|
}
|
||||||
|
for i := 0; i < len(projectList); i++ {
|
||||||
|
if isAdmin {
|
||||||
|
projectList[i].Role = models.PROJECTADMIN
|
||||||
|
}
|
||||||
|
if projectList[i].Role == models.PROJECTADMIN || projectList[i].Role == models.DEVELOPER ||
|
||||||
|
projectList[i].Role == models.GUEST {
|
||||||
|
proMap["my_project_count"]++
|
||||||
|
proMap["my_repo_count"] += getRepoCountByProject(projectList[i].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.Data["json"] = proMap
|
||||||
|
s.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
//getReposByProject returns repo numbers of specified project
|
||||||
|
func getRepoCountByProject(projectName string) int {
|
||||||
|
repoList, err := svc_utils.GetRepoFromCache()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get repo from cache, error: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var resp int
|
||||||
|
if len(projectName) > 0 {
|
||||||
|
for _, r := range repoList {
|
||||||
|
if strings.Contains(r, "/") && r[0:strings.LastIndex(r, "/")] == projectName {
|
||||||
|
resp++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//getTotalRepoCount returns total repo count
|
||||||
|
func getTotalRepoCount() int {
|
||||||
|
repoList, err := svc_utils.GetRepoFromCache()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get repo from cache, error: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(repoList)
|
||||||
|
|
||||||
|
}
|
@ -353,7 +353,7 @@ func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) {
|
func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) {
|
||||||
projects, err := GetUserRelevantProjects(currentUser.UserID)
|
projects, err := SearchProjects(currentUser.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in QueryRelevantProjects: %v", err)
|
t.Errorf("Error occurred in QueryRelevantProjects: %v", err)
|
||||||
}
|
}
|
||||||
@ -572,39 +572,6 @@ func TestIsProjectPublic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQueryProject(t *testing.T) {
|
|
||||||
query1 := models.Project{
|
|
||||||
UserID: 1,
|
|
||||||
}
|
|
||||||
projects, err := QueryProject(query1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error in Query Project: %v, query: %+v", err, query1)
|
|
||||||
}
|
|
||||||
if len(projects) != 2 {
|
|
||||||
t.Errorf("Expecting get 2 projects, but actual: %d, the list: %+v", len(projects), projects)
|
|
||||||
}
|
|
||||||
query2 := models.Project{
|
|
||||||
Public: 1,
|
|
||||||
}
|
|
||||||
projects, err = QueryProject(query2)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error in Query Project: %v, query: %+v", err, query2)
|
|
||||||
}
|
|
||||||
if len(projects) != 1 {
|
|
||||||
t.Errorf("Expecting get 1 project, but actual: %d, the list: %+v", len(projects), projects)
|
|
||||||
}
|
|
||||||
query3 := models.Project{
|
|
||||||
UserID: 9,
|
|
||||||
}
|
|
||||||
projects, err = QueryProject(query3)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error in Query Project: %v, query: %+v", err, query3)
|
|
||||||
}
|
|
||||||
if len(projects) != 0 {
|
|
||||||
t.Errorf("Expecting get 0 project, but actual: %d, the list: %+v", len(projects), projects)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetUserProjectRoles(t *testing.T) {
|
func TestGetUserProjectRoles(t *testing.T) {
|
||||||
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID)
|
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -632,20 +599,20 @@ func TestProjectPermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUserRelevantProjects(t *testing.T) {
|
func TestGetUserRelevantProjects(t *testing.T) {
|
||||||
projects, err := GetUserRelevantProjects(currentUser.UserID)
|
projects, err := GetUserRelevantProjects(currentUser.UserID, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in GetUserRelevantProjects: %v", err)
|
t.Errorf("Error occurred in GetUserRelevantProjects: %v", err)
|
||||||
}
|
}
|
||||||
if len(projects) != 2 {
|
if len(projects) != 1 {
|
||||||
t.Errorf("Expected length of relevant projects is 2, but actual: %d, the projects: %+v", len(projects), projects)
|
t.Errorf("Expected length of relevant projects is 1, but actual: %d, the projects: %+v", len(projects), projects)
|
||||||
}
|
}
|
||||||
if projects[1].Name != projectName {
|
if projects[0].Name != projectName {
|
||||||
t.Errorf("Expected project name in the list: %s, actual: %s", projectName, projects[1].Name)
|
t.Errorf("Expected project name in the list: %s, actual: %s", projectName, projects[1].Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAllProjects(t *testing.T) {
|
func TestGetAllProjects(t *testing.T) {
|
||||||
projects, err := GetAllProjects()
|
projects, err := GetAllProjects("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in GetAllProjects: %v", err)
|
t.Errorf("Error occurred in GetAllProjects: %v", err)
|
||||||
}
|
}
|
||||||
|
100
dao/project.go
100
dao/project.go
@ -79,42 +79,6 @@ func IsProjectPublic(projectName string) bool {
|
|||||||
return project.Public == 1
|
return project.Public == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryProject querys the projects based on publicity and user, disregarding the names etc.
|
|
||||||
func QueryProject(query models.Project) ([]models.Project, error) {
|
|
||||||
o := orm.NewOrm()
|
|
||||||
|
|
||||||
sql := `select distinct
|
|
||||||
p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public
|
|
||||||
from project p
|
|
||||||
left join project_member pm on p.project_id = pm.project_id
|
|
||||||
where p.deleted = 0 `
|
|
||||||
|
|
||||||
queryParam := make([]interface{}, 1)
|
|
||||||
|
|
||||||
if query.Public == 1 {
|
|
||||||
sql += ` and p.public = ?`
|
|
||||||
queryParam = append(queryParam, query.Public)
|
|
||||||
} else if isAdmin, _ := IsAdminRole(query.UserID); isAdmin == false {
|
|
||||||
sql += ` and (pm.user_id = ?) `
|
|
||||||
queryParam = append(queryParam, query.UserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if query.Name != "" {
|
|
||||||
sql += " and p.name like ? "
|
|
||||||
queryParam = append(queryParam, query.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += " order by p.name "
|
|
||||||
|
|
||||||
var r []models.Project
|
|
||||||
_, err := o.Raw(sql, queryParam).QueryRows(&r)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//ProjectExists returns whether the project exists according to its name of ID.
|
//ProjectExists returns whether the project exists according to its name of ID.
|
||||||
func ProjectExists(nameOrID interface{}) (bool, error) {
|
func ProjectExists(nameOrID interface{}) (bool, error) {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
@ -208,11 +172,11 @@ func ToggleProjectPublicity(projectID int64, publicity int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserRelevantProjects returns a project list,
|
// SearchProjects returns a project list,
|
||||||
// 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 GetUserRelevantProjects(userID int) ([]models.Project, error) {
|
func SearchProjects(userID int) ([]models.Project, error) {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
sql := `select distinct p.project_id, p.name, p.public
|
sql := `select distinct p.project_id, p.name, p.public
|
||||||
from project p
|
from project p
|
||||||
@ -228,14 +192,66 @@ func GetUserRelevantProjects(userID int) ([]models.Project, error) {
|
|||||||
return projects, nil
|
return projects, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllProjects returns all projects which are not deleted
|
// GetUserRelevantProjects returns the projects of the user which are not deleted and name like projectName
|
||||||
func GetAllProjects() ([]models.Project, error) {
|
func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, error) {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
sql := `select project_id, name, public
|
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 := make([]interface{}, 1)
|
||||||
|
queryParam = append(queryParam, userID)
|
||||||
|
if projectName != "" {
|
||||||
|
sql += " and p.name like ? "
|
||||||
|
queryParam = append(queryParam, projectName)
|
||||||
|
}
|
||||||
|
sql += " order by p.name "
|
||||||
|
var r []models.Project
|
||||||
|
_, err := o.Raw(sql, queryParam).QueryRows(&r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetPublicProjects returns all public projects whose name like projectName
|
||||||
|
func GetPublicProjects(projectName string) ([]models.Project, error) {
|
||||||
|
publicProjects, err := getProjects(1, projectName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
return publicProjects, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllProjects returns all projects which are not deleted and name like projectName
|
||||||
|
func GetAllProjects(projectName string) ([]models.Project, error) {
|
||||||
|
allProjects, err := getProjects(0, projectName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return allProjects, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProjects(public int, projectName string) ([]models.Project, error) {
|
||||||
|
o := orm.NewOrm()
|
||||||
|
sql := `select project_id, owner_id, creation_time, update_time, name, public
|
||||||
from project
|
from project
|
||||||
where deleted = 0`
|
where deleted = 0`
|
||||||
|
queryParam := make([]interface{}, 1)
|
||||||
|
if public == 1 {
|
||||||
|
sql += "and public = ?"
|
||||||
|
queryParam = append(queryParam, public)
|
||||||
|
}
|
||||||
|
if len(projectName) > 0 {
|
||||||
|
sql += " and name like ? "
|
||||||
|
queryParam = append(queryParam, projectName)
|
||||||
|
}
|
||||||
|
sql += " order by name "
|
||||||
var projects []models.Project
|
var projects []models.Project
|
||||||
if _, err := o.Raw(sql).QueryRows(&projects); err != nil {
|
if _, err := o.Raw(sql, queryParam).QueryRows(&projects); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return projects, nil
|
return projects, nil
|
||||||
|
@ -34,4 +34,6 @@ type Project struct {
|
|||||||
Togglable bool
|
Togglable bool
|
||||||
|
|
||||||
UpdateTime time.Time `orm:"update_time" json:"update_time"`
|
UpdateTime time.Time `orm:"update_time" json:"update_time"`
|
||||||
|
Role int `json:"role_id"`
|
||||||
|
RepoCount int `json:"repo_count"`
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ func initRouters() {
|
|||||||
beego.Router("/api/search", &api.SearchAPI{})
|
beego.Router("/api/search", &api.SearchAPI{})
|
||||||
beego.Router("/api/projects/:pid/members/?:mid", &api.ProjectMemberAPI{})
|
beego.Router("/api/projects/:pid/members/?:mid", &api.ProjectMemberAPI{})
|
||||||
beego.Router("/api/projects/?:id", &api.ProjectAPI{})
|
beego.Router("/api/projects/?:id", &api.ProjectAPI{})
|
||||||
|
beego.Router("/api/statistics", &api.StatisticAPI{})
|
||||||
beego.Router("/api/projects/:id/logs/filter", &api.ProjectAPI{}, "post:FilterAccessLog")
|
beego.Router("/api/projects/:id/logs/filter", &api.ProjectAPI{}, "post:FilterAccessLog")
|
||||||
beego.Router("/api/users", &api.UserAPI{})
|
beego.Router("/api/users", &api.UserAPI{})
|
||||||
beego.Router("/api/users/?:id", &api.UserAPI{})
|
beego.Router("/api/users/?:id", &api.UserAPI{})
|
||||||
|
Loading…
Reference in New Issue
Block a user