diff --git a/integrations/links_test.go b/integrations/links_test.go index 84be7e05911bf..3f645073e4bdd 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -72,19 +72,19 @@ func testLinksAsUser(userName string, t *testing.T) { "/api/swagger", "/api/v1/swagger", "/issues", - "/issues?type=your_repositories&repo=0&sort=&state=open", - "/issues?type=assigned&repo=0&sort=&state=open", - "/issues?type=created_by&repo=0&sort=&state=open", - "/issues?type=your_repositories&repo=0&sort=&state=closed", - "/issues?type=assigned&repo=0&sort=&state=closed", - "/issues?type=created_by&repo=0&sort=&state=closed", + "/issues?type=your_repositories&repos=[0]&sort=&state=open", + "/issues?type=assigned&repos=[0]&sort=&state=open", + "/issues?type=your_repositories&repos=[0]&sort=&state=closed", + "/issues?type=assigned&repos=[0]&sort=&state=closed", + "/issues?type=created_by&repos=[0]&sort=&state=closed", + "/issues?type=created_by&repos=[0]&sort=&state=open", "/pulls", - "/pulls?type=your_repositories&repo=0&sort=&state=open", - "/pulls?type=assigned&repo=0&sort=&state=open", - "/pulls?type=created_by&repo=0&sort=&state=open", - "/pulls?type=your_repositories&repo=0&sort=&state=closed", - "/pulls?type=assigned&repo=0&sort=&state=closed", - "/pulls?type=created_by&repo=0&sort=&state=closed", + "/pulls?type=your_repositories&repos=[0]&sort=&state=open", + "/pulls?type=assigned&repos=[0]&sort=&state=open", + "/pulls?type=created_by&repos=[0]&sort=&state=open", + "/pulls?type=your_repositories&repos=[0]&sort=&state=closed", + "/pulls?type=assigned&repos=[0]&sort=&state=closed", + "/pulls?type=created_by&repos=[0]&sort=&state=closed", "/notifications", "/repo/create", "/repo/migrate", diff --git a/models/issue.go b/models/issue.go index 999bd2f7a9b4d..38bff647ce756 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1618,6 +1618,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { type UserIssueStatsOptions struct { UserID int64 RepoID int64 + RepoIDs []int64 UserRepoIDs []int64 FilterMode int IsPull bool @@ -1634,6 +1635,9 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { if opts.RepoID > 0 { cond = cond.And(builder.Eq{"issue.repo_id": opts.RepoID}) } + if len(opts.RepoIDs) > 0 { + cond = cond.And(builder.In("issue.repo_id", opts.RepoIDs)) + } switch opts.FilterMode { case FilterModeAll: diff --git a/routers/user/home.go b/routers/user/home.go index 9ccd5bdb2681c..8ff82080db6f3 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -7,8 +7,11 @@ package user import ( "bytes" + "encoding/json" "fmt" + "regexp" "sort" + "strconv" "strings" "code.gitea.io/gitea/models" @@ -18,7 +21,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/Unknwon/com" + // "github.com/Unknwon/com" "github.com/keybase/go-crypto/openpgp" "github.com/keybase/go-crypto/openpgp/armor" ) @@ -192,7 +195,21 @@ func Issues(ctx *context.Context) { page = 1 } - repoID := ctx.QueryInt64("repo") + // Regexp: Match all square brackets, and plus signs in order to handle pagination + re := regexp.MustCompile(`[\[\]\+]+`) + // Replace regexp return value with commas, and split + repoIDStrings := strings.Split(re.ReplaceAllString(ctx.Query("repos"), ","), ",") + var repoIDs []int64 + for _, IDString := range repoIDStrings { + // Ensure nonempty string entries + if IDString != "" && IDString != "0" { + IDint64, err := strconv.ParseInt(IDString, 10, 64) + if err == nil { + repoIDs = append(repoIDs, IDint64) + } + } + } + isShowClosed := ctx.Query("state") == "closed" // Get repositories. @@ -230,20 +247,9 @@ func Issues(ctx *context.Context) { SortType: sortType, } - if repoID > 0 { - opts.RepoIDs = []int64{repoID} - } - switch filterMode { case models.FilterModeAll: - if repoID > 0 { - if !com.IsSliceContainsInt64(userRepoIDs, repoID) { - // force an empty result - opts.RepoIDs = []int64{-1} - } - } else { - opts.RepoIDs = userRepoIDs - } + opts.RepoIDs = userRepoIDs case models.FilterModeAssign: opts.AssigneeID = ctxUser.ID case models.FilterModeCreate: @@ -271,6 +277,10 @@ func Issues(ctx *context.Context) { } opts.LabelIDs = labelIDs + if len(repoIDs) > 0 { + opts.RepoIDs = repoIDs + } + issues, err := models.Issues(opts) if err != nil { ctx.ServerError("Issues", err) @@ -279,46 +289,41 @@ func Issues(ctx *context.Context) { showReposMap := make(map[int64]*models.Repository, len(counts)) for repoID := range counts { - repo, err := models.GetRepositoryByID(repoID) - if err != nil { - ctx.ServerError("GetRepositoryByID", err) - return - } - showReposMap[repoID] = repo - } - - if repoID > 0 { - if _, ok := showReposMap[repoID]; !ok { - repo, err := models.GetRepositoryByID(repoID) - if models.IsErrRepoNotExist(err) { - ctx.NotFound("GetRepositoryByID", err) - return - } else if err != nil { - ctx.ServerError("GetRepositoryByID", fmt.Errorf("[%d]%v", repoID, err)) - return + if repoID > 0 { + if _, ok := showReposMap[repoID]; !ok { + repo, err := models.GetRepositoryByID(repoID) + if models.IsErrRepoNotExist(err) { + ctx.NotFound("GetRepositoryByID", err) + return + } else if err != nil { + ctx.ServerError("GetRepositoryByID", fmt.Errorf("[%d]%v", repoID, err)) + return + } + showReposMap[repoID] = repo } - showReposMap[repoID] = repo - } - repo := showReposMap[repoID] + repo := showReposMap[repoID] - // Check if user has access to given repository. - perm, err := models.GetUserRepoPermission(repo, ctxUser) - if err != nil { - ctx.ServerError("GetUserRepoPermission", fmt.Errorf("[%d]%v", repoID, err)) - return - } - if !perm.CanRead(models.UnitTypeIssues) { - if log.IsTrace() { - log.Trace("Permission Denied: User %-v cannot read %-v of repo %-v\n"+ - "User in repo has Permissions: %-+v", - ctxUser, - models.UnitTypeIssues, - repo, - perm) + // Check if user has access to given repository. + perm, err := models.GetUserRepoPermission(repo, ctxUser) + if err != nil { + ctx.ServerError("GetUserRepoPermission", fmt.Errorf("[%d]%v", repoID, err)) + return + } + if !perm.CanRead(models.UnitTypeIssues) { + if log.IsTrace() { + log.Trace("Permission Denied: User %-v cannot read %-v of repo %-v\n"+ + "User in repo has Permissions: %-+v", + ctxUser, + models.UnitTypeIssues, + repo, + perm) + } + // ctx.Status(404) + // return + delete(showReposMap, repoID) + delete(counts, repoID) } - ctx.Status(404) - return } } @@ -340,7 +345,7 @@ func Issues(ctx *context.Context) { issueStats, err := models.GetUserIssueStats(models.UserIssueStatsOptions{ UserID: ctxUser.ID, - RepoID: repoID, + RepoIDs: repoIDs, UserRepoIDs: userRepoIDs, FilterMode: filterMode, IsPull: isPullList, @@ -351,11 +356,26 @@ func Issues(ctx *context.Context) { return } - var total int + allIssueStats, err := models.GetUserIssueStats(models.UserIssueStatsOptions{ + UserID: ctxUser.ID, + UserRepoIDs: userRepoIDs, + FilterMode: filterMode, + IsPull: isPullList, + IsClosed: isShowClosed, + }) + if err != nil { + ctx.ServerError("GetUserIssueStats All", err) + return + } + + var shownIssues int + var totalIssues int if !isShowClosed { - total = int(issueStats.OpenCount) + shownIssues = int(issueStats.OpenCount) + totalIssues = int(allIssueStats.OpenCount) } else { - total = int(issueStats.ClosedCount) + shownIssues = int(issueStats.ClosedCount) + totalIssues = int(allIssueStats.ClosedCount) } ctx.Data["Issues"] = issues @@ -365,8 +385,9 @@ func Issues(ctx *context.Context) { ctx.Data["IssueStats"] = issueStats ctx.Data["ViewType"] = viewType ctx.Data["SortType"] = sortType - ctx.Data["RepoID"] = repoID + ctx.Data["RepoIDs"] = repoIDs ctx.Data["IsShowClosed"] = isShowClosed + ctx.Data["TotalIssueCount"] = totalIssues if isShowClosed { ctx.Data["State"] = "closed" @@ -374,9 +395,14 @@ func Issues(ctx *context.Context) { ctx.Data["State"] = "open" } - pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5) + // Convert []int64 to string + reposParam, _ := json.Marshal(repoIDs) + + ctx.Data["ReposParam"] = string(reposParam) + + pager := context.NewPagination(shownIssues, setting.UI.IssuePagingNum, page, 5) pager.AddParam(ctx, "type", "ViewType") - pager.AddParam(ctx, "repo", "RepoID") + pager.AddParam(ctx, "repos", "ReposParam") pager.AddParam(ctx, "sort", "SortType") pager.AddParam(ctx, "state", "State") pager.AddParam(ctx, "labels", "SelectLabels") diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index b69509d7992c1..e648ca9191451 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -5,36 +5,55 @@