mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-03 01:00:08 +01:00
Merge pull request #620 from ywk253100/pagination
support pagination for listing repositories, jobs and access logs
This commit is contained in:
commit
48d4bd677a
59
api/base.go
59
api/base.go
@ -31,6 +31,11 @@ import (
|
|||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultPageSize int64 = 10
|
||||||
|
maxPageSize int64 = 100
|
||||||
|
)
|
||||||
|
|
||||||
// BaseAPI wraps common methods for controllers to host API
|
// BaseAPI wraps common methods for controllers to host API
|
||||||
type BaseAPI struct {
|
type BaseAPI struct {
|
||||||
beego.Controller
|
beego.Controller
|
||||||
@ -138,6 +143,60 @@ func (b *BaseAPI) GetIDFromURL() int64 {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set "Link" and "X-Total-Count" header for pagination request
|
||||||
|
func (b *BaseAPI) setPaginationHeader(total, page, pageSize int64) {
|
||||||
|
b.Ctx.ResponseWriter.Header().Set("X-Total-Count", strconv.FormatInt(total, 10))
|
||||||
|
|
||||||
|
link := ""
|
||||||
|
|
||||||
|
// set previous link
|
||||||
|
if page > 1 && (page-1)*pageSize <= total {
|
||||||
|
u := *(b.Ctx.Request.URL)
|
||||||
|
q := u.Query()
|
||||||
|
q.Set("page", strconv.FormatInt(page-1, 10))
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
if len(link) != 0 {
|
||||||
|
link += ", "
|
||||||
|
}
|
||||||
|
link += fmt.Sprintf("<%s>; rel=\"prev\"", u.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// set next link
|
||||||
|
if pageSize*page < total {
|
||||||
|
u := *(b.Ctx.Request.URL)
|
||||||
|
q := u.Query()
|
||||||
|
q.Set("page", strconv.FormatInt(page+1, 10))
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
if len(link) != 0 {
|
||||||
|
link += ", "
|
||||||
|
}
|
||||||
|
link += fmt.Sprintf("<%s>; rel=\"next\"", u.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(link) != 0 {
|
||||||
|
b.Ctx.ResponseWriter.Header().Set("Link", link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseAPI) getPaginationParams() (page, pageSize int64) {
|
||||||
|
page, err := b.GetInt64("page", 1)
|
||||||
|
if err != nil || page <= 0 {
|
||||||
|
b.CustomAbort(http.StatusBadRequest, "invalid page")
|
||||||
|
}
|
||||||
|
|
||||||
|
pageSize, err = b.GetInt64("page_size", defaultPageSize)
|
||||||
|
if err != nil || pageSize <= 0 {
|
||||||
|
b.CustomAbort(http.StatusBadRequest, "invalid page_size")
|
||||||
|
}
|
||||||
|
|
||||||
|
if pageSize > maxPageSize {
|
||||||
|
pageSize = maxPageSize
|
||||||
|
log.Debugf("the parameter page_size %d exceeds the max %d, set it to max", pageSize, maxPageSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
return page, pageSize
|
||||||
|
}
|
||||||
|
|
||||||
func getIsInsecure() bool {
|
func getIsInsecure() bool {
|
||||||
insecure := false
|
insecure := false
|
||||||
|
|
||||||
|
@ -238,25 +238,25 @@ func (p *ProjectAPI) ToggleProjectPublic() {
|
|||||||
func (p *ProjectAPI) FilterAccessLog() {
|
func (p *ProjectAPI) FilterAccessLog() {
|
||||||
p.userID = p.ValidateUser()
|
p.userID = p.ValidateUser()
|
||||||
|
|
||||||
var filter models.AccessLog
|
var query models.AccessLog
|
||||||
p.DecodeJSONReq(&filter)
|
p.DecodeJSONReq(&query)
|
||||||
|
|
||||||
username := filter.Username
|
query.ProjectID = p.projectID
|
||||||
keywords := filter.Keywords
|
query.Username = "%" + query.Username + "%"
|
||||||
|
query.BeginTime = time.Unix(query.BeginTimestamp, 0)
|
||||||
|
query.EndTime = time.Unix(query.EndTimestamp, 0)
|
||||||
|
|
||||||
beginTime := time.Unix(filter.BeginTimestamp, 0)
|
page, pageSize := p.getPaginationParams()
|
||||||
endTime := time.Unix(filter.EndTimestamp, 0)
|
|
||||||
|
|
||||||
query := models.AccessLog{ProjectID: p.projectID, Username: "%" + username + "%", Keywords: keywords, BeginTime: beginTime, BeginTimestamp: filter.BeginTimestamp, EndTime: endTime, EndTimestamp: filter.EndTimestamp}
|
logs, total, err := dao.GetAccessLogs(query, pageSize, pageSize*(page-1))
|
||||||
|
|
||||||
log.Infof("Query AccessLog: begin: %v, end: %v, keywords: %s", query.BeginTime, query.EndTime, query.Keywords)
|
|
||||||
|
|
||||||
accessLogList, err := dao.GetAccessLogs(query)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error occurred in GetAccessLogs, error: %v", err)
|
log.Errorf("failed to get access log: %v", err)
|
||||||
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
p.CustomAbort(http.StatusInternalServerError, "")
|
||||||
}
|
}
|
||||||
p.Data["json"] = accessLogList
|
|
||||||
|
p.setPaginationHeader(total, page, pageSize)
|
||||||
|
|
||||||
|
p.Data["json"] = logs
|
||||||
|
|
||||||
p.ServeJSON()
|
p.ServeJSON()
|
||||||
}
|
}
|
||||||
|
@ -56,43 +56,28 @@ func (ra *RepJobAPI) Prepare() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// List filters jobs according to the policy and repository
|
// List filters jobs according to the parameters
|
||||||
func (ra *RepJobAPI) List() {
|
func (ra *RepJobAPI) List() {
|
||||||
var policyID int64
|
|
||||||
var repository, status string
|
|
||||||
var startTime, endTime *time.Time
|
|
||||||
var num int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
policyIDStr := ra.GetString("policy_id")
|
policyID, err := ra.GetInt64("policy_id")
|
||||||
if len(policyIDStr) != 0 {
|
if err != nil || policyID <= 0 {
|
||||||
policyID, err = strconv.ParseInt(policyIDStr, 10, 64)
|
ra.CustomAbort(http.StatusBadRequest, "invalid policy_id")
|
||||||
if err != nil || policyID <= 0 {
|
|
||||||
ra.CustomAbort(http.StatusBadRequest, fmt.Sprintf("invalid policy ID: %s", policyIDStr))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
numStr := ra.GetString("num")
|
policy, err := dao.GetRepPolicy(policyID)
|
||||||
if len(numStr) != 0 {
|
if err != nil {
|
||||||
num, err = strconv.Atoi(numStr)
|
log.Errorf("failed to get policy %d: %v", policyID, err)
|
||||||
if err != nil {
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
ra.CustomAbort(http.StatusBadRequest, fmt.Sprintf("invalid num: %s", numStr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if num <= 0 {
|
|
||||||
num = 200
|
|
||||||
}
|
}
|
||||||
|
|
||||||
endTimeStr := ra.GetString("end_time")
|
if policy == nil {
|
||||||
if len(endTimeStr) != 0 {
|
ra.CustomAbort(http.StatusNotFound, fmt.Sprintf("policy %d not found", policyID))
|
||||||
i, err := strconv.ParseInt(endTimeStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
ra.CustomAbort(http.StatusBadRequest, "invalid end_time")
|
|
||||||
}
|
|
||||||
t := time.Unix(i, 0)
|
|
||||||
endTime = &t
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repository := ra.GetString("repository")
|
||||||
|
status := ra.GetString("status")
|
||||||
|
|
||||||
|
var startTime *time.Time
|
||||||
startTimeStr := ra.GetString("start_time")
|
startTimeStr := ra.GetString("start_time")
|
||||||
if len(startTimeStr) != 0 {
|
if len(startTimeStr) != 0 {
|
||||||
i, err := strconv.ParseInt(startTimeStr, 10, 64)
|
i, err := strconv.ParseInt(startTimeStr, 10, 64)
|
||||||
@ -103,21 +88,29 @@ func (ra *RepJobAPI) List() {
|
|||||||
startTime = &t
|
startTime = &t
|
||||||
}
|
}
|
||||||
|
|
||||||
if startTime == nil && endTime == nil {
|
var endTime *time.Time
|
||||||
// if start_time and end_time are both null, list jobs of last 10 days
|
endTimeStr := ra.GetString("end_time")
|
||||||
t := time.Now().UTC().AddDate(0, 0, -10)
|
if len(endTimeStr) != 0 {
|
||||||
startTime = &t
|
i, err := strconv.ParseInt(endTimeStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
ra.CustomAbort(http.StatusBadRequest, "invalid end_time")
|
||||||
|
}
|
||||||
|
t := time.Unix(i, 0)
|
||||||
|
endTime = &t
|
||||||
}
|
}
|
||||||
|
|
||||||
repository = ra.GetString("repository")
|
page, pageSize := ra.getPaginationParams()
|
||||||
status = ra.GetString("status")
|
|
||||||
|
|
||||||
jobs, err := dao.FilterRepJobs(policyID, repository, status, startTime, endTime, num)
|
jobs, total, err := dao.FilterRepJobs(policyID, repository, status,
|
||||||
|
startTime, endTime, pageSize, pageSize*(page-1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to filter jobs according policy ID %d, repository %s, status %s: %v", policyID, repository, status, err)
|
log.Errorf("failed to filter jobs according policy ID %d, repository %s, status %s, start time %v, end time %v: %v",
|
||||||
ra.RenderError(http.StatusInternalServerError, "Failed to query job")
|
policyID, repository, status, startTime, endTime, err)
|
||||||
return
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ra.setPaginationHeader(total, page, pageSize)
|
||||||
|
|
||||||
ra.Data["json"] = jobs
|
ra.Data["json"] = jobs
|
||||||
ra.ServeJSON()
|
ra.ServeJSON()
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
@ -34,6 +35,7 @@ import (
|
|||||||
|
|
||||||
registry_error "github.com/vmware/harbor/utils/registry/error"
|
registry_error "github.com/vmware/harbor/utils/registry/error"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/utils"
|
||||||
"github.com/vmware/harbor/utils/registry/auth"
|
"github.com/vmware/harbor/utils/registry/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,23 +48,23 @@ type RepositoryAPI struct {
|
|||||||
// Get ...
|
// Get ...
|
||||||
func (ra *RepositoryAPI) Get() {
|
func (ra *RepositoryAPI) Get() {
|
||||||
projectID, err := ra.GetInt64("project_id")
|
projectID, err := ra.GetInt64("project_id")
|
||||||
if err != nil {
|
if err != nil || projectID <= 0 {
|
||||||
log.Errorf("Failed to get project id, error: %v", err)
|
ra.CustomAbort(http.StatusBadRequest, "invalid project_id")
|
||||||
ra.RenderError(http.StatusBadRequest, "Invalid project id")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p, err := dao.GetProjectByID(projectID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in GetProjectById, error: %v", err)
|
|
||||||
ra.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
|
||||||
}
|
|
||||||
if p == nil {
|
|
||||||
log.Warningf("Project with Id: %d does not exist", projectID)
|
|
||||||
ra.RenderError(http.StatusNotFound, "")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Public == 0 {
|
page, pageSize := ra.getPaginationParams()
|
||||||
|
|
||||||
|
project, err := dao.GetProjectByID(projectID)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get project %d: %v", projectID, err)
|
||||||
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if project == nil {
|
||||||
|
ra.CustomAbort(http.StatusNotFound, fmt.Sprintf("project %d not found", projectID))
|
||||||
|
}
|
||||||
|
|
||||||
|
if project.Public == 0 {
|
||||||
var userID int
|
var userID int
|
||||||
|
|
||||||
if svc_utils.VerifySecret(ra.Ctx.Request) {
|
if svc_utils.VerifySecret(ra.Ctx.Request) {
|
||||||
@ -72,37 +74,47 @@ func (ra *RepositoryAPI) Get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !checkProjectPermission(userID, projectID) {
|
if !checkProjectPermission(userID, projectID) {
|
||||||
ra.RenderError(http.StatusForbidden, "")
|
ra.CustomAbort(http.StatusForbidden, "")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repoList, err := cache.GetRepoFromCache()
|
repoList, err := cache.GetRepoFromCache()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to get repo from cache, error: %v", err)
|
log.Errorf("failed to get repository from cache: %v", err)
|
||||||
ra.RenderError(http.StatusInternalServerError, "internal sever error")
|
ra.CustomAbort(http.StatusInternalServerError, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
projectName := p.Name
|
repositories := []string{}
|
||||||
|
|
||||||
q := ra.GetString("q")
|
q := ra.GetString("q")
|
||||||
var resp []string
|
for _, repo := range repoList {
|
||||||
if len(q) > 0 {
|
pn, rest := utils.ParseRepository(repo)
|
||||||
for _, r := range repoList {
|
if project.Name != pn {
|
||||||
if strings.Contains(r, "/") && strings.Contains(r[strings.LastIndex(r, "/")+1:], q) && r[0:strings.LastIndex(r, "/")] == projectName {
|
continue
|
||||||
resp = append(resp, r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ra.Data["json"] = resp
|
|
||||||
} else if len(projectName) > 0 {
|
if len(q) != 0 && !strings.Contains(rest, q) {
|
||||||
for _, r := range repoList {
|
continue
|
||||||
if strings.Contains(r, "/") && r[0:strings.LastIndex(r, "/")] == projectName {
|
|
||||||
resp = append(resp, r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ra.Data["json"] = resp
|
|
||||||
} else {
|
repositories = append(repositories, repo)
|
||||||
ra.Data["json"] = repoList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.Data["json"] = repositories
|
||||||
ra.ServeJSON()
|
ra.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,67 +39,78 @@ func AddAccessLog(accessLog models.AccessLog) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//GetAccessLogs gets access logs according to different conditions
|
//GetAccessLogs gets access logs according to different conditions
|
||||||
func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) {
|
func GetAccessLogs(query models.AccessLog, limit, offset int64) ([]models.AccessLog, int64, error) {
|
||||||
|
|
||||||
o := GetOrmer()
|
o := GetOrmer()
|
||||||
sql := `select a.log_id, u.username, a.repo_name, a.repo_tag, a.operation, a.op_time
|
|
||||||
from access_log a left join user u on a.user_id = u.user_id
|
condition := ` from access_log a left join user u on a.user_id = u.user_id
|
||||||
where a.project_id = ? `
|
where a.project_id = ? `
|
||||||
queryParam := make([]interface{}, 1)
|
queryParam := make([]interface{}, 1)
|
||||||
queryParam = append(queryParam, accessLog.ProjectID)
|
queryParam = append(queryParam, query.ProjectID)
|
||||||
|
|
||||||
if accessLog.UserID != 0 {
|
if query.UserID != 0 {
|
||||||
sql += ` and a.user_id = ? `
|
condition += ` and a.user_id = ? `
|
||||||
queryParam = append(queryParam, accessLog.UserID)
|
queryParam = append(queryParam, query.UserID)
|
||||||
}
|
}
|
||||||
if accessLog.Operation != "" {
|
if query.Operation != "" {
|
||||||
sql += ` and a.operation = ? `
|
condition += ` and a.operation = ? `
|
||||||
queryParam = append(queryParam, accessLog.Operation)
|
queryParam = append(queryParam, query.Operation)
|
||||||
}
|
}
|
||||||
if accessLog.Username != "" {
|
if query.Username != "" {
|
||||||
sql += ` and u.username like ? `
|
condition += ` and u.username like ? `
|
||||||
queryParam = append(queryParam, accessLog.Username)
|
queryParam = append(queryParam, query.Username)
|
||||||
}
|
}
|
||||||
if accessLog.RepoName != "" {
|
if query.RepoName != "" {
|
||||||
sql += ` and a.repo_name = ? `
|
condition += ` and a.repo_name = ? `
|
||||||
queryParam = append(queryParam, accessLog.RepoName)
|
queryParam = append(queryParam, query.RepoName)
|
||||||
}
|
}
|
||||||
if accessLog.RepoTag != "" {
|
if query.RepoTag != "" {
|
||||||
sql += ` and a.repo_tag = ? `
|
condition += ` and a.repo_tag = ? `
|
||||||
queryParam = append(queryParam, accessLog.RepoTag)
|
queryParam = append(queryParam, query.RepoTag)
|
||||||
}
|
}
|
||||||
if accessLog.Keywords != "" {
|
if query.Keywords != "" {
|
||||||
sql += ` and a.operation in ( `
|
condition += ` and a.operation in ( `
|
||||||
keywordList := strings.Split(accessLog.Keywords, "/")
|
keywordList := strings.Split(query.Keywords, "/")
|
||||||
num := len(keywordList)
|
num := len(keywordList)
|
||||||
for i := 0; i < num; i++ {
|
for i := 0; i < num; i++ {
|
||||||
if keywordList[i] != "" {
|
if keywordList[i] != "" {
|
||||||
if i == num-1 {
|
if i == num-1 {
|
||||||
sql += `?)`
|
condition += `?)`
|
||||||
} else {
|
} else {
|
||||||
sql += `?,`
|
condition += `?,`
|
||||||
}
|
}
|
||||||
queryParam = append(queryParam, keywordList[i])
|
queryParam = append(queryParam, keywordList[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if accessLog.BeginTimestamp > 0 {
|
if query.BeginTimestamp > 0 {
|
||||||
sql += ` and a.op_time >= ? `
|
condition += ` and a.op_time >= ? `
|
||||||
queryParam = append(queryParam, accessLog.BeginTime)
|
queryParam = append(queryParam, query.BeginTime)
|
||||||
}
|
}
|
||||||
if accessLog.EndTimestamp > 0 {
|
if query.EndTimestamp > 0 {
|
||||||
sql += ` and a.op_time <= ? `
|
condition += ` and a.op_time <= ? `
|
||||||
queryParam = append(queryParam, accessLog.EndTime)
|
queryParam = append(queryParam, query.EndTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql += ` order by a.op_time desc `
|
condition += ` order by a.op_time desc `
|
||||||
|
|
||||||
var accessLogList []models.AccessLog
|
totalSQL := `select count(*) ` + condition
|
||||||
_, err := o.Raw(sql, queryParam).QueryRows(&accessLogList)
|
|
||||||
|
logs := []models.AccessLog{}
|
||||||
|
|
||||||
|
var total int64
|
||||||
|
if err := o.Raw(totalSQL, queryParam).QueryRow(&total); err != nil {
|
||||||
|
return logs, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
condition = paginateForRawSQL(condition, limit, offset)
|
||||||
|
|
||||||
|
recordsSQL := `select a.log_id, u.username, a.repo_name, a.repo_tag, a.operation, a.op_time ` + condition
|
||||||
|
_, err := o.Raw(recordsSQL, queryParam).QueryRows(&logs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return logs, 0, err
|
||||||
}
|
}
|
||||||
return accessLogList, nil
|
|
||||||
|
return logs, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessLog ...
|
// AccessLog ...
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package dao
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
@ -44,7 +45,7 @@ func GenerateRandomString() (string, error) {
|
|||||||
|
|
||||||
//InitDB initializes the database
|
//InitDB initializes the database
|
||||||
func InitDB() {
|
func InitDB() {
|
||||||
// orm.Debug = true
|
// orm.Debug = true
|
||||||
orm.RegisterDriver("mysql", orm.DRMySQL)
|
orm.RegisterDriver("mysql", orm.DRMySQL)
|
||||||
addr := os.Getenv("MYSQL_HOST")
|
addr := os.Getenv("MYSQL_HOST")
|
||||||
port := os.Getenv("MYSQL_PORT")
|
port := os.Getenv("MYSQL_PORT")
|
||||||
@ -89,3 +90,7 @@ func GetOrmer() orm.Ormer {
|
|||||||
})
|
})
|
||||||
return globalOrm
|
return globalOrm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func paginateForRawSQL(sql string, limit, offset int64) string {
|
||||||
|
return fmt.Sprintf("%s limit %d offset %d", sql, limit, offset)
|
||||||
|
}
|
||||||
|
@ -420,7 +420,7 @@ func TestGetAccessLog(t *testing.T) {
|
|||||||
UserID: currentUser.UserID,
|
UserID: currentUser.UserID,
|
||||||
ProjectID: currentProject.ProjectID,
|
ProjectID: currentProject.ProjectID,
|
||||||
}
|
}
|
||||||
accessLogs, err := GetAccessLogs(queryAccessLog)
|
accessLogs, _, err := GetAccessLogs(queryAccessLog, 1000, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in GetAccessLog: %v", err)
|
t.Errorf("Error occurred in GetAccessLog: %v", err)
|
||||||
}
|
}
|
||||||
@ -448,7 +448,7 @@ func TestAddAccessLog(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in AddAccessLog: %v", err)
|
t.Errorf("Error occurred in AddAccessLog: %v", err)
|
||||||
}
|
}
|
||||||
accessLogList, err = GetAccessLogs(accessLog)
|
accessLogList, _, err = GetAccessLogs(accessLog, 1000, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in GetAccessLog: %v", err)
|
t.Errorf("Error occurred in GetAccessLog: %v", err)
|
||||||
}
|
}
|
||||||
@ -477,7 +477,7 @@ func TestAccessLog(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in AccessLog: %v", err)
|
t.Errorf("Error occurred in AccessLog: %v", err)
|
||||||
}
|
}
|
||||||
accessLogList, err = GetAccessLogs(accessLog)
|
accessLogList, _, err = GetAccessLogs(accessLog, 1000, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in GetAccessLog: %v", err)
|
t.Errorf("Error occurred in GetAccessLog: %v", err)
|
||||||
}
|
}
|
||||||
@ -1178,7 +1178,7 @@ func TestGetRepJobByPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFilterRepJobs(t *testing.T) {
|
func TestFilterRepJobs(t *testing.T) {
|
||||||
jobs, err := FilterRepJobs(policyID, "", "", nil, nil, 1000)
|
jobs, _, err := FilterRepJobs(policyID, "", "", nil, nil, 1000, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occured in FilterRepJobs: %v, policy ID: %d", err, policyID)
|
t.Errorf("Error occured in FilterRepJobs: %v, policy ID: %d", err, policyID)
|
||||||
return
|
return
|
||||||
|
@ -312,12 +312,14 @@ func GetRepJobByPolicy(policyID int64) ([]*models.RepJob, error) {
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterRepJobs filters jobs by repo and policy ID
|
// FilterRepJobs ...
|
||||||
func FilterRepJobs(policyID int64, repository, status string, startTime,
|
func FilterRepJobs(policyID int64, repository, status string, startTime,
|
||||||
endTime *time.Time, limit int) ([]*models.RepJob, error) {
|
endTime *time.Time, limit, offset int64) ([]*models.RepJob, int64, error) {
|
||||||
o := GetOrmer()
|
|
||||||
|
jobs := []*models.RepJob{}
|
||||||
|
|
||||||
|
qs := GetOrmer().QueryTable(new(models.RepJob))
|
||||||
|
|
||||||
qs := o.QueryTable(new(models.RepJob))
|
|
||||||
if policyID != 0 {
|
if policyID != 0 {
|
||||||
qs = qs.Filter("PolicyID", policyID)
|
qs = qs.Filter("PolicyID", policyID)
|
||||||
}
|
}
|
||||||
@ -327,32 +329,28 @@ func FilterRepJobs(policyID int64, repository, status string, startTime,
|
|||||||
if len(status) != 0 {
|
if len(status) != 0 {
|
||||||
qs = qs.Filter("Status__icontains", status)
|
qs = qs.Filter("Status__icontains", status)
|
||||||
}
|
}
|
||||||
|
|
||||||
if startTime != nil {
|
if startTime != nil {
|
||||||
fmt.Printf("%v\n", startTime)
|
|
||||||
qs = qs.Filter("CreationTime__gte", startTime)
|
qs = qs.Filter("CreationTime__gte", startTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if endTime != nil {
|
if endTime != nil {
|
||||||
fmt.Printf("%v\n", endTime)
|
|
||||||
qs = qs.Filter("CreationTime__lte", endTime)
|
qs = qs.Filter("CreationTime__lte", endTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if limit != 0 {
|
|
||||||
qs = qs.Limit(limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
qs = qs.OrderBy("-UpdateTime")
|
qs = qs.OrderBy("-UpdateTime")
|
||||||
|
|
||||||
var jobs []*models.RepJob
|
total, err := qs.Count()
|
||||||
_, err := qs.All(&jobs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return jobs, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = qs.Limit(limit).Offset(offset).All(&jobs)
|
||||||
|
if err != nil {
|
||||||
|
return jobs, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
genTagListForJob(jobs...)
|
genTagListForJob(jobs...)
|
||||||
|
|
||||||
return jobs, nil
|
return jobs, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepJobToStop get jobs that are possibly being handled by workers of a certain policy.
|
// GetRepJobToStop get jobs that are possibly being handled by workers of a certain policy.
|
||||||
|
@ -17,9 +17,10 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/vmware/harbor/utils/log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VerifySecret verifies the UI_SECRET cookie in a http request.
|
// VerifySecret verifies the UI_SECRET cookie in a http request.
|
||||||
@ -27,7 +28,7 @@ func VerifySecret(r *http.Request) bool {
|
|||||||
secret := os.Getenv("UI_SECRET")
|
secret := os.Getenv("UI_SECRET")
|
||||||
c, err := r.Cookie("uisecret")
|
c, err := r.Cookie("uisecret")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to get secret cookie, error: %v", err)
|
log.Warningf("Failed to get secret cookie, error: %v", err)
|
||||||
}
|
}
|
||||||
return c != nil && c.Value == secret
|
return c != nil && c.Value == secret
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,8 @@ type Repository struct {
|
|||||||
|
|
||||||
// GetProject parses the repository and return the name of project.
|
// GetProject parses the repository and return the name of project.
|
||||||
func (r *Repository) GetProject() string {
|
func (r *Repository) GetProject() string {
|
||||||
if !strings.ContainsRune(r.Name, '/') {
|
project, _ := ParseRepository(r.Name)
|
||||||
return ""
|
return project
|
||||||
}
|
|
||||||
return r.Name[0:strings.LastIndex(r.Name, "/")]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatEndpoint formats endpoint
|
// FormatEndpoint formats endpoint
|
||||||
@ -55,3 +53,17 @@ func ParseEndpoint(endpoint string) (*url.URL, error) {
|
|||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseRepository splits a repository into two parts: project and rest
|
||||||
|
func ParseRepository(repository string) (project, rest string) {
|
||||||
|
repository = strings.TrimLeft(repository, "/")
|
||||||
|
repository = strings.TrimRight(repository, "/")
|
||||||
|
if !strings.ContainsRune(repository, '/') {
|
||||||
|
rest = repository
|
||||||
|
return
|
||||||
|
}
|
||||||
|
index := strings.LastIndex(repository, "/")
|
||||||
|
project = repository[0:index]
|
||||||
|
rest = repository[index+1:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
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 utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -7,3 +22,42 @@ import (
|
|||||||
func TestMain(t *testing.T) {
|
func TestMain(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseRepository(t *testing.T) {
|
||||||
|
repository := "library/ubuntu"
|
||||||
|
project, rest := ParseRepository(repository)
|
||||||
|
if project != "library" {
|
||||||
|
t.Errorf("unexpected project: %s != %s", project, "library")
|
||||||
|
}
|
||||||
|
if rest != "ubuntu" {
|
||||||
|
t.Errorf("unexpected rest: %s != %s", rest, "ubuntu")
|
||||||
|
}
|
||||||
|
|
||||||
|
repository = "library/test/ubuntu"
|
||||||
|
project, rest = ParseRepository(repository)
|
||||||
|
if project != "library/test" {
|
||||||
|
t.Errorf("unexpected project: %s != %s", project, "library/test")
|
||||||
|
}
|
||||||
|
if rest != "ubuntu" {
|
||||||
|
t.Errorf("unexpected rest: %s != %s", rest, "ubuntu")
|
||||||
|
}
|
||||||
|
|
||||||
|
repository = "ubuntu"
|
||||||
|
project, rest = ParseRepository(repository)
|
||||||
|
if project != "" {
|
||||||
|
t.Errorf("unexpected project: [%s] != [%s]", project, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if rest != "ubuntu" {
|
||||||
|
t.Errorf("unexpected rest: %s != %s", rest, "ubuntu")
|
||||||
|
}
|
||||||
|
|
||||||
|
repository = ""
|
||||||
|
project, rest = ParseRepository(repository)
|
||||||
|
if project != "" {
|
||||||
|
t.Errorf("unexpected project: [%s] != [%s]", project, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if rest != "" {
|
||||||
|
t.Errorf("unexpected rest: [%s] != [%s]", rest, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user