mirror of
https://github.com/goharbor/harbor.git
synced 2025-03-02 10:41:59 +01:00
Merge pull request #207 from wemeya/master
add statistics api for projects and repositories
This commit is contained in:
commit
91ef155da5
@ -113,23 +113,50 @@ func (p *ProjectAPI) Head() {
|
||||
|
||||
// Get ...
|
||||
func (p *ProjectAPI) Get() {
|
||||
queryProject := models.Project{UserID: p.userID}
|
||||
var projectList []models.Project
|
||||
projectName := p.GetString("project_name")
|
||||
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 {
|
||||
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.")
|
||||
}
|
||||
for i := 0; i < len(projectList); i++ {
|
||||
if isProjectAdmin(p.userID, projectList[i].ProjectID) {
|
||||
projectList[i].Togglable = true
|
||||
if public != 1 {
|
||||
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.ServeJSON()
|
||||
|
@ -55,13 +55,13 @@ func (s *SearchAPI) Get() {
|
||||
var projects []models.Project
|
||||
|
||||
if isSysAdmin {
|
||||
projects, err = dao.GetAllProjects()
|
||||
projects, err = dao.GetAllProjects("")
|
||||
if err != nil {
|
||||
log.Errorf("failed to get all projects: %v", err)
|
||||
s.CustomAbort(http.StatusInternalServerError, "internal error")
|
||||
}
|
||||
} else {
|
||||
projects, err = dao.GetUserRelevantProjects(userID)
|
||||
projects, err = dao.SearchProjects(userID)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get user %d 's relevant projects: %v", userID, err)
|
||||
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) {
|
||||
projects, err := GetUserRelevantProjects(currentUser.UserID)
|
||||
projects, err := SearchProjects(currentUser.UserID)
|
||||
if err != nil {
|
||||
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) {
|
||||
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID)
|
||||
if err != nil {
|
||||
@ -632,20 +599,20 @@ func TestProjectPermission(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetUserRelevantProjects(t *testing.T) {
|
||||
projects, err := GetUserRelevantProjects(currentUser.UserID)
|
||||
projects, err := GetUserRelevantProjects(currentUser.UserID, "")
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetUserRelevantProjects: %v", err)
|
||||
}
|
||||
if len(projects) != 2 {
|
||||
t.Errorf("Expected length of relevant projects is 2, but actual: %d, the projects: %+v", len(projects), projects)
|
||||
if len(projects) != 1 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllProjects(t *testing.T) {
|
||||
projects, err := GetAllProjects()
|
||||
projects, err := GetAllProjects("")
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func ProjectExists(nameOrID interface{}) (bool, error) {
|
||||
o := orm.NewOrm()
|
||||
@ -208,11 +172,11 @@ func ToggleProjectPublicity(projectID int64, publicity int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// GetUserRelevantProjects returns a project list,
|
||||
// SearchProjects returns a project list,
|
||||
// which satisfies the following conditions:
|
||||
// 1. the project is not deleted
|
||||
// 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()
|
||||
sql := `select distinct p.project_id, p.name, p.public
|
||||
from project p
|
||||
@ -228,14 +192,66 @@ func GetUserRelevantProjects(userID int) ([]models.Project, error) {
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
// GetAllProjects returns all projects which are not deleted
|
||||
func GetAllProjects() ([]models.Project, error) {
|
||||
// GetUserRelevantProjects returns the projects of the user which are not deleted and name like projectName
|
||||
func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, error) {
|
||||
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
|
||||
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
|
||||
if _, err := o.Raw(sql).QueryRows(&projects); err != nil {
|
||||
if _, err := o.Raw(sql, queryParam).QueryRows(&projects); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projects, nil
|
||||
|
@ -34,4 +34,6 @@ type Project struct {
|
||||
Togglable bool
|
||||
|
||||
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/projects/:pid/members/?:mid", &api.ProjectMemberAPI{})
|
||||
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/users", &api.UserAPI{})
|
||||
beego.Router("/api/users/?:id", &api.UserAPI{})
|
||||
|
Loading…
Reference in New Issue
Block a user