Merge pull request #721 from ywk253100/page

Add pagination support for listing projects
This commit is contained in:
Wenkai Yin 2016-08-29 11:37:20 +08:00 committed by GitHub
commit 4977a2c77e
7 changed files with 152 additions and 70 deletions

View File

@ -154,13 +154,15 @@ func (p *ProjectAPI) Get() {
// List ...
func (p *ProjectAPI) List() {
var projectList []models.Project
projectName := p.GetString("project_name")
if len(projectName) > 0 {
projectName = "%" + projectName + "%"
}
var total int64
var public int
var err error
page, pageSize := p.getPaginationParams()
var projectList []models.Project
projectName := p.GetString("project_name")
isPublic := p.GetString("is_public")
if len(isPublic) > 0 {
public, err = strconv.Atoi(isPublic)
@ -171,7 +173,16 @@ func (p *ProjectAPI) List() {
}
isAdmin := false
if public == 1 {
projectList, err = dao.GetPublicProjects(projectName)
total, err = dao.GetTotalOfProjects(projectName, 1)
if err != nil {
log.Errorf("failed to get total of projects: %v", err)
p.CustomAbort(http.StatusInternalServerError, "")
}
projectList, err = dao.GetProjects(projectName, 1, pageSize, pageSize*(page-1))
if err != nil {
log.Errorf("failed to get projects: %v", err)
p.CustomAbort(http.StatusInternalServerError, "")
}
} else {
//if the request is not for public projects, user must login or provide credential
p.userID = p.ValidateUser()
@ -181,15 +192,30 @@ func (p *ProjectAPI) List() {
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
if isAdmin {
projectList, err = dao.GetAllProjects(projectName)
total, err = dao.GetTotalOfProjects(projectName)
if err != nil {
log.Errorf("failed to get total of projects: %v", err)
p.CustomAbort(http.StatusInternalServerError, "")
}
projectList, err = dao.GetProjects(projectName, pageSize, pageSize*(page-1))
if err != nil {
log.Errorf("failed to get projects: %v", err)
p.CustomAbort(http.StatusInternalServerError, "")
}
} else {
projectList, err = dao.GetUserRelevantProjects(p.userID, projectName)
total, err = dao.GetTotalOfUserRelevantProjects(p.userID, projectName)
if err != nil {
log.Errorf("failed to get total of projects: %v", err)
p.CustomAbort(http.StatusInternalServerError, "")
}
projectList, err = dao.GetUserRelevantProjects(p.userID, projectName, pageSize, pageSize*(page-1))
if err != nil {
log.Errorf("failed to get projects: %v", err)
p.CustomAbort(http.StatusInternalServerError, "")
}
}
}
if err != nil {
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 public != 1 {
if isAdmin {
@ -201,6 +227,8 @@ func (p *ProjectAPI) List() {
}
projectList[i].RepoCount = getRepoCountByProject(projectList[i].Name)
}
p.setPaginationHeader(total, page, pageSize)
p.Data["json"] = projectList
p.ServeJSON()
}

View File

@ -55,7 +55,7 @@ func (s *SearchAPI) Get() {
var projects []models.Project
if isSysAdmin {
projects, err = dao.GetAllProjects("")
projects, err = dao.GetProjects("")
if err != nil {
log.Errorf("failed to get all projects: %v", err)
s.CustomAbort(http.StatusInternalServerError, "internal error")

View File

@ -45,7 +45,7 @@ func (s *StatisticAPI) Get() {
}
var projectList []models.Project
if isAdmin {
projectList, err = dao.GetAllProjects("")
projectList, err = dao.GetProjects("")
} else {
projectList, err = dao.GetUserRelevantProjects(s.userID, "")
}
@ -59,7 +59,7 @@ func (s *StatisticAPI) Get() {
proMap["public_project_count"] = 0
proMap["public_repo_count"] = 0
var publicProjects []models.Project
publicProjects, err = dao.GetPublicProjects("")
publicProjects, err = dao.GetProjects("", 1)
if err != nil {
log.Errorf("Error occured in QueryPublicProject, error: %v", err)
s.CustomAbort(http.StatusInternalServerError, "Internal error.")

View File

@ -609,6 +609,17 @@ func TestProjectPermission(t *testing.T) {
}
}
func TestGetTotalOfUserRelevantProjects(t *testing.T) {
total, err := GetTotalOfUserRelevantProjects(currentUser.UserID, "")
if err != nil {
t.Fatalf("failed to get total of user relevant projects: %v", err)
}
if total != 1 {
t.Errorf("unexpected total: %d != 1", total)
}
}
func TestGetUserRelevantProjects(t *testing.T) {
projects, err := GetUserRelevantProjects(currentUser.UserID, "")
if err != nil {
@ -622,8 +633,19 @@ func TestGetUserRelevantProjects(t *testing.T) {
}
}
func TestGetAllProjects(t *testing.T) {
projects, err := GetAllProjects("")
func TestGetTotalOfProjects(t *testing.T) {
total, err := GetTotalOfProjects("")
if err != nil {
t.Fatalf("failed to get total of projects: %v", err)
}
if total != 2 {
t.Errorf("unexpected total: %d != 2", total)
}
}
func TestGetProjects(t *testing.T) {
projects, err := GetProjects("")
if err != nil {
t.Errorf("Error occurred in GetAllProjects: %v", err)
}
@ -636,7 +658,7 @@ func TestGetAllProjects(t *testing.T) {
}
func TestGetPublicProjects(t *testing.T) {
projects, err := GetPublicProjects("")
projects, err := GetProjects("", 1)
if err != nil {
t.Errorf("Error occurred in getProjects: %v", err)
}

View File

@ -182,66 +182,98 @@ func SearchProjects(userID int) ([]models.Project, error) {
return projects, nil
}
// GetUserRelevantProjects returns the projects of the user which are not deleted and name like projectName
func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, error) {
//GetTotalOfUserRelevantProjects returns the total count of
// user relevant projects
func GetTotalOfUserRelevantProjects(userID int, projectName string,
public ...int) (int64, error) {
o := GetOrmer()
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= ?`
sql := `select count(*) 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 := []interface{}{}
queryParam = append(queryParam, userID)
if projectName != "" {
sql += " and p.name like ? "
queryParam = append(queryParam, projectName)
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
var total int64
err := o.Raw(sql, queryParam).QueryRow(&total)
return total, err
}
//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
// GetUserRelevantProjects returns the user relevant projects
// args[0]: public, args[1]: limit, args[2]: offset
func GetUserRelevantProjects(userID int, projectName string, args ...int64) ([]models.Project, error) {
return getProjects(userID, projectName, args...)
}
// 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
// GetTotalOfProjects returns the total count of projects
func GetTotalOfProjects(name string, public ...int) (int64, error) {
qs := GetOrmer().
QueryTable(new(models.Project)).
Filter("Deleted", 0)
if len(name) > 0 {
qs = qs.Filter("Name__icontains", name)
}
return allProjects, nil
if len(public) > 0 {
qs = qs.Filter("Public", public[0])
}
return qs.Count()
}
func getProjects(public int, projectName string) ([]models.Project, error) {
// GetProjects returns project list
// args[0]: public, args[1]: limit, args[2]: offset
func GetProjects(name string, args ...int64) ([]models.Project, error) {
return getProjects(0, name, args...)
}
func getProjects(userID int, name string, args ...int64) ([]models.Project, error) {
projects := []models.Project{}
o := GetOrmer()
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)
sql := ""
queryParam := []interface{}{}
if userID != 0 { //get user's projects
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 = append(queryParam, userID)
} else { // get all projects
sql = `select * from project p where p.deleted = 0 `
}
if len(projectName) > 0 {
sql += " and name like ? "
queryParam = append(queryParam, projectName)
if name != "" {
sql += ` and p.name like ? `
queryParam = append(queryParam, "%"+name+"%")
}
sql += " order by name "
var projects []models.Project
if _, err := o.Raw(sql, queryParam).QueryRows(&projects); err != nil {
return nil, err
switch len(args) {
case 1:
sql += ` and p.public = ?`
queryParam = append(queryParam, args[0])
sql += ` order by p.name `
case 2:
sql += ` order by p.name `
sql = paginateForRawSQL(sql, args[0], args[1])
case 3:
sql += ` and p.public = ?`
queryParam = append(queryParam, args[0])
sql += ` order by p.name `
sql = paginateForRawSQL(sql, args[1], args[2])
}
return projects, nil
_, err := o.Raw(sql, queryParam).QueryRows(&projects)
return projects, err
}

View File

@ -336,13 +336,13 @@ func FilterRepJobs(policyID int64, repository, status string, startTime,
qs = qs.Filter("CreationTime__lte", endTime)
}
qs = qs.OrderBy("-UpdateTime")
total, err := qs.Count()
if err != nil {
return jobs, 0, err
}
qs = qs.OrderBy("-UpdateTime")
_, err = qs.Limit(limit).Offset(offset).All(&jobs)
if err != nil {
return jobs, 0, err

View File

@ -25,17 +25,17 @@ type Project struct {
OwnerID int `orm:"column(owner_id)" json:"owner_id"`
Name string `orm:"column(name)" json:"name"`
CreationTime time.Time `orm:"column(creation_time)" json:"creation_time"`
CreationTimeStr string `json:"creation_time_str"`
CreationTimeStr string `orm:"-" json:"creation_time_str"`
Deleted int `orm:"column(deleted)" json:"deleted"`
//UserID int `json:"UserId"`
OwnerName string `json:"owner_name"`
OwnerName string `orm:"-" json:"owner_name"`
Public int `orm:"column(public)" json:"public"`
//This field does not have correspondent column in DB, this is just for UI to disable button
Togglable bool
Togglable bool `orm:"-"`
UpdateTime time.Time `orm:"update_time" json:"update_time"`
Role int `json:"current_user_role_id"`
RepoCount int `json:"repo_count"`
Role int `orm:"-" json:"current_user_role_id"`
RepoCount int `orm:"-" json:"repo_count"`
}
// ProjectSorter holds an array of projects