From 1b83c0b076c890491e83db2eeb99fed4785c8975 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Fri, 26 May 2017 14:58:00 +0800 Subject: [PATCH] support pagination in GET recent logs API --- docs/swagger.yaml | 18 +- src/common/dao/accesslog.go | 175 ++++-------------- src/common/dao/dao_test.go | 38 ++-- src/common/dao/project.go | 10 +- src/common/models/accesslog.go | 15 +- src/common/models/project.go | 4 +- src/common/security/rbac/context_test.go | 4 +- src/ui/api/harborapi_test.go | 8 +- src/ui/api/log.go | 84 +++++---- src/ui/api/log_test.go | 78 +------- src/ui/api/project.go | 54 ++++-- src/ui/api/statistic.go | 4 +- src/ui/projectmanager/db/pm.go | 8 +- src/ui/projectmanager/db/pm_test.go | 12 +- src/ui/projectmanager/pm.go | 4 +- .../lib/src/service/access-log.service.ts | 2 +- src/ui_ng/src/app/log/audit-log.service.ts | 2 +- 17 files changed, 194 insertions(+), 326 deletions(-) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ea853af59..c2a57e99a 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -861,24 +861,18 @@ paths: description: | This endpoint let user see the recent operation logs of the projects which he is member of parameters: - - name: lines + - name: page in: query type: integer format: int32 required: false - description: The number of logs to be shown, default is 10 if lines, start_time, end_time are not provided. - - name: start_time + description: The page nubmer, default is 1. + - name: page_size in: query type: integer - format: int64 + format: int32 required: false - description: The start time of logs to be shown in unix timestap - - name: end_time - in: query - type: integer - format: int64 - required: false - description: The end time of logs to be shown in unix timestap + description: The size of per page, default is 10, maximum is 100. tags: - Products responses: @@ -889,7 +883,7 @@ paths: items: $ref: '#/definitions/AccessLog' 400: - description: Bad request because of invalid parameter of lines or start_time or end_time. + description: Bad request because of invalid parameters. 401: description: User need to login first. 500: diff --git a/src/common/dao/accesslog.go b/src/common/dao/accesslog.go index 9470213bd..654744648 100644 --- a/src/common/dao/accesslog.go +++ b/src/common/dao/accesslog.go @@ -15,8 +15,7 @@ package dao import ( - "strings" - + "github.com/astaxie/beego/orm" "github.com/vmware/harbor/src/common/models" "github.com/vmware/harbor/src/common/utils/log" ) @@ -29,155 +28,61 @@ func AddAccessLog(accessLog models.AccessLog) error { } // GetTotalOfAccessLogs ... -func GetTotalOfAccessLogs(query models.AccessLog) (int64, error) { - o := GetOrmer() - - queryParam := []interface{}{} - - sql := `select count(*) from access_log al - where al.project_id = ?` - queryParam = append(queryParam, query.ProjectID) - - sql += genFilterClauses(query, &queryParam) - - var total int64 - if err := o.Raw(sql, queryParam).QueryRow(&total); err != nil { - return 0, err - } - return total, nil +func GetTotalOfAccessLogs(query *models.LogQueryParam) (int64, error) { + return logQueryConditions(query).Count() } //GetAccessLogs gets access logs according to different conditions -func GetAccessLogs(query models.AccessLog, limit, offset int64) ([]models.AccessLog, error) { - o := GetOrmer() +func GetAccessLogs(query *models.LogQueryParam) ([]models.AccessLog, error) { + qs := logQueryConditions(query).OrderBy("-op_time") - queryParam := []interface{}{} - sql := `select al.log_id, al.username, al.repo_name, - al.repo_tag, al.operation, al.op_time - from access_log al - where al.project_id = ? ` - queryParam = append(queryParam, query.ProjectID) + if query != nil && query.Pagination != nil { + size := query.Pagination.Size + if size > 0 { + qs = qs.Limit(size) - sql += genFilterClauses(query, &queryParam) - - sql += ` order by al.op_time desc ` - - sql = paginateForRawSQL(sql, limit, offset) - - logs := []models.AccessLog{} - _, err := o.Raw(sql, queryParam).QueryRows(&logs) - if err != nil { - return logs, err - } - - return logs, nil -} - -func genFilterClauses(query models.AccessLog, queryParam *[]interface{}) string { - sql := "" - - if query.Username != "" { - sql += ` and al.username like ? ` - *queryParam = append(*queryParam, "%"+escape(query.Username)+"%") - } - - if query.Operation != "" { - sql += ` and al.operation = ? ` - *queryParam = append(*queryParam, query.Operation) - } - if query.RepoName != "" { - sql += ` and al.repo_name = ? ` - *queryParam = append(*queryParam, query.RepoName) - } - if query.RepoTag != "" { - sql += ` and al.repo_tag = ? ` - *queryParam = append(*queryParam, query.RepoTag) - } - if query.Keywords != "" { - sql += ` and al.operation in ( ` - keywordList := strings.Split(query.Keywords, "/") - num := len(keywordList) - for i := 0; i < num; i++ { - if keywordList[i] != "" { - if i == num-1 { - sql += `?)` - } else { - sql += `?,` - } - *queryParam = append(*queryParam, keywordList[i]) + page := query.Pagination.Page + if page > 0 { + qs = qs.Offset((page - 1) * size) } } } - if query.BeginTimestamp > 0 { - sql += ` and al.op_time >= ? ` - *queryParam = append(*queryParam, query.BeginTime) - } - if query.EndTimestamp > 0 { - sql += ` and al.op_time <= ? ` - *queryParam = append(*queryParam, query.EndTime) - } - return sql + logs := []models.AccessLog{} + _, err := qs.All(&logs) + return logs, err } -//GetRecentLogs returns recent logs according to parameters -func GetRecentLogs(username string, linesNum int, startTime, endTime string) ([]models.AccessLog, error) { - logs := []models.AccessLog{} +func logQueryConditions(query *models.LogQueryParam) orm.QuerySeter { + qs := GetOrmer().QueryTable(&models.AccessLog{}) - isAdmin, err := IsAdminRole(username) - if err != nil { - return logs, err + if query == nil { + return qs } - queryParam := []interface{}{} - sql := `select log_id, username, project_id, repo_name, repo_tag, GUID, operation, op_time - from access_log ` - - hasWhere := false - if !isAdmin { - sql += ` where project_id in - (select distinct project_id - from project_member pm - join user u - on pm.user_id = u.user_id - where u.username = ?) ` - queryParam = append(queryParam, username) - hasWhere = true + if len(query.ProjectIDs) > 0 { + qs = qs.Filter("project_id__in", query.ProjectIDs) + } + if len(query.Username) != 0 { + qs = qs.Filter("username__contains", query.Username) + } + if len(query.Repository) != 0 { + qs = qs.Filter("repo_name", query.Repository) + } + if len(query.Tag) != 0 { + qs = qs.Filter("repo_tag", query.Tag) + } + if len(query.Operations) > 0 { + qs = qs.Filter("operation__in", query.Operations) + } + if query.BeginTime != nil { + qs = qs.Filter("op_time__gte", query.BeginTime) + } + if query.EndTime != nil { + qs = qs.Filter("op_time__lte", query.EndTime) } - if startTime != "" { - if hasWhere { - sql += " and op_time >= ?" - } else { - sql += " where op_time >= ?" - hasWhere = true - } - - queryParam = append(queryParam, startTime) - } - - if endTime != "" { - if hasWhere { - sql += " and op_time <= ?" - } else { - sql += " where op_time <= ?" - hasWhere = true - } - - queryParam = append(queryParam, endTime) - } - - sql += " order by op_time desc" - if linesNum != 0 { - sql += " limit ?" - queryParam = append(queryParam, linesNum) - } - - _, err = GetOrmer().Raw(sql, queryParam).QueryRows(&logs) - if err != nil { - return logs, err - } - return logs, nil + return qs } // CountPull ... diff --git a/src/common/dao/dao_test.go b/src/common/dao/dao_test.go index b7a18d21a..67c1c78d4 100644 --- a/src/common/dao/dao_test.go +++ b/src/common/dao/dao_test.go @@ -570,11 +570,11 @@ func TestGetAccessLog(t *testing.T) { t.Errorf("failed to add access log: %v", err) } - queryAccessLog := models.AccessLog{ - Username: currentUser.Username, - ProjectID: currentProject.ProjectID, + query := &models.LogQueryParam{ + Username: currentUser.Username, + ProjectIDs: []int64{currentProject.ProjectID}, } - accessLogs, err := GetAccessLogs(queryAccessLog, 1000, 0) + accessLogs, err := GetAccessLogs(query) if err != nil { t.Errorf("Error occurred in GetAccessLog: %v", err) } @@ -587,11 +587,11 @@ func TestGetAccessLog(t *testing.T) { } func TestGetTotalOfAccessLogs(t *testing.T) { - queryAccessLog := models.AccessLog{ - Username: currentUser.Username, - ProjectID: currentProject.ProjectID, + query := &models.LogQueryParam{ + Username: currentUser.Username, + ProjectIDs: []int64{currentProject.ProjectID}, } - total, err := GetTotalOfAccessLogs(queryAccessLog) + total, err := GetTotalOfAccessLogs(query) if err != nil { t.Fatalf("failed to get total of access log: %v", err) } @@ -617,7 +617,15 @@ func TestAddAccessLog(t *testing.T) { if err != nil { t.Errorf("Error occurred in AddAccessLog: %v", err) } - accessLogList, err = GetAccessLogs(accessLog, 1000, 0) + + query := &models.LogQueryParam{ + Username: accessLog.Username, + ProjectIDs: []int64{accessLog.ProjectID}, + Repository: accessLog.RepoName, + Tag: accessLog.RepoTag, + Operations: []string{accessLog.Operation}, + } + accessLogList, err = GetAccessLogs(query) if err != nil { t.Errorf("Error occurred in GetAccessLog: %v", err) } @@ -819,7 +827,7 @@ func TestGetProjects(t *testing.T) { func TestGetPublicProjects(t *testing.T) { value := true - projects, err := GetProjects(&models.QueryParam{ + projects, err := GetProjects(&models.ProjectQueryParam{ Public: &value, }) if err != nil { @@ -953,16 +961,6 @@ func TestChangeUserProfile(t *testing.T) { } } -func TestGetRecentLogs(t *testing.T) { - logs, err := GetRecentLogs(currentUser.Username, 10, "2016-05-13 00:00:00", time.Now().String()) - if err != nil { - t.Errorf("error occured in getting recent logs, error: %v", err) - } - if len(logs) <= 0 { - t.Errorf("get logs error, expected: %d, actual: %d", 1, len(logs)) - } -} - var targetID, policyID, policyID2, policyID3, jobID, jobID2, jobID3 int64 func TestAddRepTarget(t *testing.T) { diff --git a/src/common/dao/project.go b/src/common/dao/project.go index 319f423be..07b4a562c 100644 --- a/src/common/dao/project.go +++ b/src/common/dao/project.go @@ -183,7 +183,7 @@ func SearchProjects(userID int) ([]*models.Project, error) { // GetTotalOfProjects returns the total count of projects // according to the query conditions -func GetTotalOfProjects(query *models.QueryParam) (int64, error) { +func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) { var ( owner string @@ -203,7 +203,7 @@ func GetTotalOfProjects(query *models.QueryParam) (int64, error) { } } - sql, params := queryConditions(owner, name, public, member, role) + sql, params := projectQueryConditions(owner, name, public, member, role) sql = `select count(*) ` + sql @@ -213,7 +213,7 @@ func GetTotalOfProjects(query *models.QueryParam) (int64, error) { } // GetProjects returns a project list according to the query conditions -func GetProjects(query *models.QueryParam) ([]*models.Project, error) { +func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) { var ( owner string @@ -239,7 +239,7 @@ func GetProjects(query *models.QueryParam) ([]*models.Project, error) { } } - sql, params := queryConditions(owner, name, public, member, role) + sql, params := projectQueryConditions(owner, name, public, member, role) sql = `select distinct p.project_id, p.name, p.public, p.owner_id, p.creation_time, p.update_time ` + sql @@ -258,7 +258,7 @@ func GetProjects(query *models.QueryParam) ([]*models.Project, error) { return projects, err } -func queryConditions(owner, name string, public *bool, member string, +func projectQueryConditions(owner, name string, public *bool, member string, role int) (string, []interface{}) { params := []interface{}{} diff --git a/src/common/models/accesslog.go b/src/common/models/accesslog.go index f151a3077..4a52d073a 100644 --- a/src/common/models/accesslog.go +++ b/src/common/models/accesslog.go @@ -30,8 +30,19 @@ type AccessLog struct { Operation string `orm:"column(operation)" json:"operation"` OpTime time.Time `orm:"column(op_time)" json:"op_time"` Keywords string `orm:"-" json:"keywords"` - BeginTime time.Time `orm:"-"` BeginTimestamp int64 `orm:"-" json:"begin_timestamp"` - EndTime time.Time `orm:"-"` EndTimestamp int64 `orm:"-" json:"end_timestamp"` } + +// LogQueryParam is used to set query conditions when listing +// access logs. +type LogQueryParam struct { + ProjectIDs []int64 // the IDs of projects to which the operation is done + Username string // the operator's username of the log + Repository string // repository name + Tag string // tag name + Operations []string // operations + BeginTime *time.Time // the time after which the operation is done + EndTime *time.Time // the time before which the operation is doen + Pagination *Pagination // pagination information +} diff --git a/src/common/models/project.go b/src/common/models/project.go index 558299169..db7f62d5f 100644 --- a/src/common/models/project.go +++ b/src/common/models/project.go @@ -58,7 +58,7 @@ func (ps *ProjectSorter) Swap(i, j int) { ps.Projects[i], ps.Projects[j] = ps.Projects[j], ps.Projects[i] } -// QueryParam can be used to set query parameters when listing projects. +// ProjectQueryParam can be used to set query parameters when listing projects. // The query condition will be set in the query if its corresponding field // is not nil. Leave it empty if you don't want to apply this condition. // @@ -69,7 +69,7 @@ func (ps *ProjectSorter) Swap(i, j int) { // List all public projects the owner of which is user1: query := &QueryParam{Owner:"user1",Public:true} // List projects which user1 is member of: query := &QueryParam{Member:&Member{Name:"user1"}} // List projects which user1 is the project admin : query := &QueryParam{Memeber:&Member{Name:"user1",Role:1}} -type QueryParam struct { +type ProjectQueryParam struct { Name string // the name of project Owner string // the username of project owner Public *bool // the project is public or not, can be ture, false and nil diff --git a/src/common/security/rbac/context_test.go b/src/common/security/rbac/context_test.go index 817c73977..d3baa518d 100644 --- a/src/common/security/rbac/context_test.go +++ b/src/common/security/rbac/context_test.go @@ -106,12 +106,12 @@ func (f *fakePM) Update(projectIDOrName interface{}, project *models.Project) er } // nil implement -func (f *fakePM) GetAll(*models.QueryParam) ([]*models.Project, error) { +func (f *fakePM) GetAll(*models.ProjectQueryParam) ([]*models.Project, error) { return []*models.Project{}, nil } // nil implement -func (f *fakePM) GetTotal(*models.QueryParam) (int64, error) { +func (f *fakePM) GetTotal(*models.ProjectQueryParam) (int64, error) { return 0, nil } diff --git a/src/ui/api/harborapi_test.go b/src/ui/api/harborapi_test.go index 56cc0cf8d..db8f32276 100644 --- a/src/ui/api/harborapi_test.go +++ b/src/ui/api/harborapi_test.go @@ -226,20 +226,14 @@ func (a testapi) StatisticGet(user usrInfo) (int, apilib.StatisticMap, error) { return httpStatusCode, successPayload, err } -func (a testapi) LogGet(user usrInfo, startTime, endTime, lines string) (int, []apilib.AccessLog, error) { +func (a testapi) LogGet(user usrInfo) (int, []apilib.AccessLog, error) { _sling := sling.New().Get(a.basePath) // create path and map variables path := "/api/logs/" fmt.Printf("logs path: %s\n", path) _sling = _sling.Path(path) - type QueryParams struct { - StartTime string `url:"start_time,omitempty"` - EndTime string `url:"end_time,omitempty"` - Lines string `url:"lines,omitempty"` - } - _sling = _sling.QueryStruct(&QueryParams{StartTime: startTime, EndTime: endTime, Lines: lines}) var successPayload []apilib.AccessLog code, body, err := request(_sling, jsonAcceptHeader, user) if 200 == code && nil == err { diff --git a/src/ui/api/log.go b/src/ui/api/log.go index 0c1809f62..ec92bfbdf 100644 --- a/src/ui/api/log.go +++ b/src/ui/api/log.go @@ -15,18 +15,17 @@ package api import ( - "net/http" - "strconv" - "time" + "fmt" "github.com/vmware/harbor/src/common/dao" "github.com/vmware/harbor/src/common/models" - "github.com/vmware/harbor/src/common/utils/log" ) //LogAPI handles request api/logs type LogAPI struct { BaseController + username string + isSysAdmin bool } //Prepare validates the URL and the user @@ -36,53 +35,58 @@ func (l *LogAPI) Prepare() { l.HandleUnauthorized() return } + l.username = l.SecurityCtx.GetUsername() + l.isSysAdmin = l.SecurityCtx.IsSysAdmin() } //Get returns the recent logs according to parameters func (l *LogAPI) Get() { - var err error - startTime := l.GetString("start_time") - if len(startTime) != 0 { - i, err := strconv.ParseInt(startTime, 10, 64) - if err != nil { - log.Errorf("Parse startTime to int error, err: %v", err) - l.CustomAbort(http.StatusBadRequest, "startTime is not a valid integer") - } - startTime = time.Unix(i, 0).String() + page, size := l.GetPaginationParams() + query := &models.LogQueryParam{ + Pagination: &models.Pagination{ + Page: page, + Size: size, + }, } - endTime := l.GetString("end_time") - if len(endTime) != 0 { - j, err := strconv.ParseInt(endTime, 10, 64) + if !l.isSysAdmin { + projects, err := l.ProjectMgr.GetByMember(l.username) if err != nil { - log.Errorf("Parse endTime to int error, err: %v", err) - l.CustomAbort(http.StatusBadRequest, "endTime is not a valid integer") + l.HandleInternalServerError(fmt.Sprintf( + "failed to get projects of user %s: %v", l.username, err)) + return } - endTime = time.Unix(j, 0).String() + + if len(projects) == 0 { + l.SetPaginationHeader(0, page, size) + l.Data["json"] = nil + l.ServeJSON() + return + } + + ids := []int64{} + for _, project := range projects { + ids = append(ids, project.ProjectID) + } + query.ProjectIDs = ids } - var linesNum int - lines := l.GetString("lines") - if len(lines) != 0 { - linesNum, err = strconv.Atoi(lines) - if err != nil { - log.Errorf("Get parameters error--lines, err: %v", err) - l.CustomAbort(http.StatusBadRequest, "bad request of lines") - } - if linesNum <= 0 { - log.Warning("lines must be a positive integer") - l.CustomAbort(http.StatusBadRequest, "lines is 0 or negative") - } - } else if len(startTime) == 0 && len(endTime) == 0 { - linesNum = 10 - } - - var logList []models.AccessLog - logList, err = dao.GetRecentLogs(l.SecurityCtx.GetUsername(), linesNum, startTime, endTime) + total, err := dao.GetTotalOfAccessLogs(query) if err != nil { - log.Errorf("Get recent logs error, err: %v", err) - l.CustomAbort(http.StatusInternalServerError, "Internal error") + l.HandleInternalServerError(fmt.Sprintf( + "failed to get total of access logs: %v", err)) + return } - l.Data["json"] = logList + + logs, err := dao.GetAccessLogs(query) + if err != nil { + l.HandleInternalServerError(fmt.Sprintf( + "failed to get access logs: %v", err)) + return + } + + l.SetPaginationHeader(total, page, size) + + l.Data["json"] = logs l.ServeJSON() } diff --git a/src/ui/api/log_test.go b/src/ui/api/log_test.go index f7e53a719..e86367bd9 100644 --- a/src/ui/api/log_test.go +++ b/src/ui/api/log_test.go @@ -15,11 +15,11 @@ package api import ( "fmt" - "github.com/stretchr/testify/assert" - "github.com/vmware/harbor/tests/apitests/apilib" "strconv" "testing" - "time" + + "github.com/stretchr/testify/assert" + "github.com/vmware/harbor/tests/apitests/apilib" ) func TestLogGet(t *testing.T) { @@ -29,12 +29,11 @@ func TestLogGet(t *testing.T) { apiTest := newHarborAPI() //prepare for test - + CommonAddUser() var project apilib.ProjectReq project.ProjectName = "my_project" project.Public = 1 - now := fmt.Sprintf("%v", time.Now().Unix()) - statusCode, result, err := apiTest.LogGet(*admin, "0", now, "1000") + statusCode, result, err := apiTest.LogGet(*testUser) if err != nil { t.Error("Error while get log information", err.Error()) t.Log(err) @@ -46,7 +45,7 @@ func TestLogGet(t *testing.T) { fmt.Println("result", result) //add the project first. fmt.Println("add the project first.") - reply, err := apiTest.ProjectsPost(*admin, project) + reply, err := apiTest.ProjectsPost(*testUser, project) if err != nil { t.Error("Error while creat project", err.Error()) t.Log(err) @@ -54,8 +53,7 @@ func TestLogGet(t *testing.T) { assert.Equal(int(201), reply, "Case 2: Project creation status should be 201") } //case 1: right parameters, expect the right output - now = fmt.Sprintf("%v", time.Now().Unix()) - statusCode, result, err = apiTest.LogGet(*admin, "0", now, "1000") + statusCode, result, err = apiTest.LogGet(*testUser) if err != nil { t.Error("Error while get log information", err.Error()) t.Log(err) @@ -71,64 +69,6 @@ func TestLogGet(t *testing.T) { } } fmt.Println("log ", result) - //case 2: wrong format of start_time parameter, expect the wrong output - statusCode, result, err = apiTest.LogGet(*admin, "ss", now, "3") - if err != nil { - t.Error("Error occured while get log information since the format of start_time parameter is not right.", err.Error()) - t.Log(err) - } else { - assert.Equal(int(400), statusCode, "Http status code should be 400") - } - - //case 3: wrong format of end_time parameter, expect the wrong output - statusCode, result, err = apiTest.LogGet(*admin, "0", "cc", "3") - if err != nil { - t.Error("Error occured while get log information since the format of end_time parameter is not right.", err.Error()) - t.Log(err) - } else { - assert.Equal(int(400), statusCode, "Http status code should be 400") - } - - //case 4: wrong format of lines parameter, expect the wrong output - statusCode, result, err = apiTest.LogGet(*admin, "0", now, "s") - if err != nil { - t.Error("Error occured while get log information since the format of lines parameter is not right.", err.Error()) - t.Log(err) - } else { - assert.Equal(int(400), statusCode, "Http status code should be 400") - } - - //case 5: wrong format of lines parameter, expect the wrong output - statusCode, result, err = apiTest.LogGet(*admin, "0", now, "-5") - if err != nil { - t.Error("Error occured while get log information since the format of lines parameter is not right.", err.Error()) - t.Log(err) - } else { - assert.Equal(int(400), statusCode, "Http status code should be 400") - } - - //case 6: all parameters are null, expect the right output - statusCode, result, err = apiTest.LogGet(*admin, "", "", "") - if err != nil { - t.Error("Error while get log information", err.Error()) - t.Log(err) - } else { - //default get 10 logs - if logNum+1 >= 10 { - logNum = 10 - } else { - logNum++ - } - assert.Equal(logNum, len(result), "lines of logs should be equal") - num, index := getLog(result) - if num != 1 { - assert.Equal(1, num, "add my_project log number should be 1") - } else { - assert.Equal("my_project/", result[index].RepoName, "RepoName should be equal") - assert.Equal("N/A", result[index].RepoTag, "RepoTag should be equal") - assert.Equal("create", result[index].Operation, "Operation should be equal") - } - } //get the project var projects []apilib.Project @@ -144,7 +84,7 @@ func TestLogGet(t *testing.T) { //delete the project projectID := strconv.Itoa(int(addProjectID)) - httpStatusCode, err = apiTest.ProjectsDelete(*admin, projectID) + httpStatusCode, err = apiTest.ProjectsDelete(*testUser, projectID) if err != nil { t.Error("Error while delete project", err.Error()) t.Log(err) @@ -152,7 +92,7 @@ func TestLogGet(t *testing.T) { assert.Equal(int(200), httpStatusCode, "Case 1: Project creation status should be 200") //t.Log(result) } - + CommonDelUser() fmt.Printf("\n") } diff --git a/src/ui/api/project.go b/src/ui/api/project.go index 347663b6d..36596c2cb 100644 --- a/src/ui/api/project.go +++ b/src/ui/api/project.go @@ -18,6 +18,7 @@ import ( "fmt" "net/http" "regexp" + "strings" "github.com/vmware/harbor/src/common" "github.com/vmware/harbor/src/common/dao" @@ -258,7 +259,7 @@ func projectContainsPolicy(id int64) (bool, error) { // TODO refacter pattern to: // /api/repositories?owner=xxx&name=xxx&public=true&member=xxx&role=1&page=1&size=3 func (p *ProjectAPI) List() { - query := &models.QueryParam{} + query := &models.ProjectQueryParam{} query.Name = p.GetString("project_name") public := p.GetString("is_public") @@ -382,28 +383,49 @@ func (p *ProjectAPI) FilterAccessLog() { var query models.AccessLog p.DecodeJSONReq(&query) - query.ProjectID = p.project.ProjectID - query.BeginTime = time.Unix(query.BeginTimestamp, 0) - query.EndTime = time.Unix(query.EndTimestamp, 0) - - page, pageSize := p.GetPaginationParams() - - total, err := dao.GetTotalOfAccessLogs(query) - if err != nil { - log.Errorf("failed to get total of access log: %v", err) - p.CustomAbort(http.StatusInternalServerError, "") + queryParm := &models.LogQueryParam{ + ProjectIDs: []int64{p.project.ProjectID}, + Username: query.Username, + Repository: query.RepoName, + Tag: query.RepoTag, } - logs, err := dao.GetAccessLogs(query, pageSize, pageSize*(page-1)) + if len(query.Keywords) > 0 { + queryParm.Operations = strings.Split(query.Keywords, "/") + } + + if query.BeginTimestamp > 0 { + beginTime := time.Unix(query.BeginTimestamp, 0) + queryParm.BeginTime = &beginTime + } + + if query.EndTimestamp > 0 { + endTime := time.Unix(query.EndTimestamp, 0) + queryParm.EndTime = &endTime + } + + page, pageSize := p.GetPaginationParams() + queryParm.Pagination = &models.Pagination{ + Page: page, + Size: pageSize, + } + + total, err := dao.GetTotalOfAccessLogs(queryParm) if err != nil { - log.Errorf("failed to get access log: %v", err) - p.CustomAbort(http.StatusInternalServerError, "") + p.HandleInternalServerError(fmt.Sprintf( + "failed to get total of access log: %v", err)) + return + } + + logs, err := dao.GetAccessLogs(queryParm) + if err != nil { + p.HandleInternalServerError(fmt.Sprintf( + "failed to get access log: %v", err)) + return } p.SetPaginationHeader(total, page, pageSize) - p.Data["json"] = logs - p.ServeJSON() } diff --git a/src/ui/api/statistic.go b/src/ui/api/statistic.go index 4183b0a80..59af50c30 100644 --- a/src/ui/api/statistic.go +++ b/src/ui/api/statistic.go @@ -53,7 +53,7 @@ func (s *StatisticAPI) Prepare() { func (s *StatisticAPI) Get() { statistic := map[string]int64{} t := true - n, err := dao.GetTotalOfProjects(&models.QueryParam{ + n, err := dao.GetTotalOfProjects(&models.ProjectQueryParam{ Public: &t, }) if err != nil { @@ -99,7 +99,7 @@ func (s *StatisticAPI) Get() { log.Errorf("failed to get user %d: %v", s.userID, err) s.CustomAbort(http.StatusInternalServerError, "") } - n, err := dao.GetTotalOfProjects(&models.QueryParam{ + n, err := dao.GetTotalOfProjects(&models.ProjectQueryParam{ Member: &models.Member{ Name: user.Username, }, diff --git a/src/ui/projectmanager/db/pm.go b/src/ui/projectmanager/db/pm.go index 96736d8f7..c96986fcc 100644 --- a/src/ui/projectmanager/db/pm.go +++ b/src/ui/projectmanager/db/pm.go @@ -107,7 +107,7 @@ func (p *ProjectManager) GetRoles(username string, projectIDOrName interface{}) // GetPublic returns all public projects func (p *ProjectManager) GetPublic() ([]*models.Project, error) { t := true - return p.GetAll(&models.QueryParam{ + return p.GetAll(&models.ProjectQueryParam{ Public: &t, }) } @@ -115,7 +115,7 @@ func (p *ProjectManager) GetPublic() ([]*models.Project, error) { // GetByMember returns all projects which the user is a member of func (p *ProjectManager) GetByMember(username string) ( []*models.Project, error) { - return p.GetAll(&models.QueryParam{ + return p.GetAll(&models.ProjectQueryParam{ Member: &models.Member{ Name: username, }, @@ -190,13 +190,13 @@ func (p *ProjectManager) Update(projectIDOrName interface{}, } // GetAll returns a project list according to the query parameters -func (p *ProjectManager) GetAll(query *models.QueryParam) ( +func (p *ProjectManager) GetAll(query *models.ProjectQueryParam) ( []*models.Project, error) { return dao.GetProjects(query) } // GetTotal returns the total count according to the query parameters -func (p *ProjectManager) GetTotal(query *models.QueryParam) ( +func (p *ProjectManager) GetTotal(query *models.ProjectQueryParam) ( int64, error) { return dao.GetTotalOfProjects(query) } diff --git a/src/ui/projectmanager/db/pm_test.go b/src/ui/projectmanager/db/pm_test.go index 24255887b..d5bc9a9f3 100644 --- a/src/ui/projectmanager/db/pm_test.go +++ b/src/ui/projectmanager/db/pm_test.go @@ -229,14 +229,14 @@ func TestGetTotal(t *testing.T) { defer pm.Delete(id) // get by name - total, err := pm.GetTotal(&models.QueryParam{ + total, err := pm.GetTotal(&models.ProjectQueryParam{ Name: "get_total_test", }) assert.Nil(t, err) assert.Equal(t, int64(1), total) // get by owner - total, err = pm.GetTotal(&models.QueryParam{ + total, err = pm.GetTotal(&models.ProjectQueryParam{ Owner: "admin", }) assert.Nil(t, err) @@ -244,7 +244,7 @@ func TestGetTotal(t *testing.T) { // get by public value := true - total, err = pm.GetTotal(&models.QueryParam{ + total, err = pm.GetTotal(&models.ProjectQueryParam{ Public: &value, }) assert.Nil(t, err) @@ -263,14 +263,14 @@ func TestGetAll(t *testing.T) { defer pm.Delete(id) // get by name - projects, err := pm.GetAll(&models.QueryParam{ + projects, err := pm.GetAll(&models.ProjectQueryParam{ Name: "get_all_test", }) assert.Nil(t, err) assert.Equal(t, id, projects[0].ProjectID) // get by owner - projects, err = pm.GetAll(&models.QueryParam{ + projects, err = pm.GetAll(&models.ProjectQueryParam{ Owner: "admin", }) assert.Nil(t, err) @@ -285,7 +285,7 @@ func TestGetAll(t *testing.T) { // get by public value := true - projects, err = pm.GetAll(&models.QueryParam{ + projects, err = pm.GetAll(&models.ProjectQueryParam{ Public: &value, }) assert.Nil(t, err) diff --git a/src/ui/projectmanager/pm.go b/src/ui/projectmanager/pm.go index 14ad4af2f..a426b56a0 100644 --- a/src/ui/projectmanager/pm.go +++ b/src/ui/projectmanager/pm.go @@ -33,7 +33,7 @@ type ProjectManager interface { Delete(projectIDOrName interface{}) error Update(projectIDOrName interface{}, project *models.Project) error // GetAll returns a project list according to the query parameters - GetAll(query *models.QueryParam) ([]*models.Project, error) + GetAll(query *models.ProjectQueryParam) ([]*models.Project, error) // GetTotal returns the total count according to the query parameters - GetTotal(query *models.QueryParam) (int64, error) + GetTotal(query *models.ProjectQueryParam) (int64, error) } diff --git a/src/ui_ng/lib/src/service/access-log.service.ts b/src/ui_ng/lib/src/service/access-log.service.ts index fd1ac4ba5..4baf9f267 100644 --- a/src/ui_ng/lib/src/service/access-log.service.ts +++ b/src/ui_ng/lib/src/service/access-log.service.ts @@ -67,7 +67,7 @@ export class AccessLogDefaultService extends AccessLogService { url = '/api/logs'; } - return this.http.get(url+`?lines=${lines}`, HTTP_JSON_OPTIONS).toPromise() + return this.http.get(url+`?page_size=${lines}`, HTTP_JSON_OPTIONS).toPromise() .then(response => response.json() as AccessLog[]) .catch(error => Promise.reject(error)); } diff --git a/src/ui_ng/src/app/log/audit-log.service.ts b/src/ui_ng/src/app/log/audit-log.service.ts index b88a8017b..4b1d8f11a 100644 --- a/src/ui_ng/src/app/log/audit-log.service.ts +++ b/src/ui_ng/src/app/log/audit-log.service.ts @@ -49,7 +49,7 @@ export class AuditLogService { } getRecentLogs(lines: number): Observable { - return this.http.get(logEndpoint + "?lines=" + lines, this.httpOptions) + return this.http.get(logEndpoint + "?page_size=" + lines, this.httpOptions) .map(response => response.json() as AuditLog[]) .catch(error => Observable.throw(error)); }