Files
gitea/routers/web/repo/activity.go
Copilot 45b4fffae4 refactor: use named Permission field in Repository struct instead of anonymous embedding (#37441)
The `Repository` struct in `services/context/repo.go` embedded
`access_model.Permission` anonymously, causing all permission methods to
be promoted directly onto `Repository`. This made it unclear at call
sites whether a method belonged to `Repository` itself or to its
embedded `Permission`.

### Changes

- **`services/context/repo.go`**: Replace anonymous
`access_model.Permission` with named field `Permission
access_model.Permission`
- **49 files** updated to route permission method calls through the
named field:

```go
// Before
ctx.Repo.IsAdmin()
ctx.Repo.CanWrite(unit.TypeCode)
ctx.Repo.CanReadIssuesOrPulls(isPull)
slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite)

// After
ctx.Repo.Permission.IsAdmin()
ctx.Repo.Permission.CanWrite(unit.TypeCode)
ctx.Repo.Permission.CanReadIssuesOrPulls(isPull)
slices.ContainsFunc(unitTypes, ctx.Repo.Permission.CanWrite)
```

Methods defined directly on `*Repository` (`CanWriteToBranch`,
`CanCreateBranch`, etc.) are unchanged.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
2026-04-26 20:18:28 +00:00

115 lines
3.4 KiB
Go

// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"net/http"
"time"
activities_model "code.gitea.io/gitea/models/activities"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
)
const (
tplActivity templates.TplName = "repo/activity"
)
// Activity render the page to show repository latest changes
func Activity(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.activity")
ctx.Data["PageIsActivity"] = true
ctx.Data["PageIsPulse"] = true
timeUntil := time.Now()
period, timeFrom := "weekly", timeUntil.Add(-time.Hour*168)
switch ctx.PathParam("period") {
case "daily":
period, timeFrom = "daily", timeUntil.Add(-time.Hour*24)
case "halfweekly":
period, timeFrom = "halfweekly", timeUntil.Add(-time.Hour*72)
case "weekly":
period, timeFrom = "weekly", timeUntil.Add(-time.Hour*168)
case "monthly":
period, timeFrom = "monthly", timeUntil.AddDate(0, -1, 0)
case "quarterly":
period, timeFrom = "quarterly", timeUntil.AddDate(0, -3, 0)
case "semiyearly":
period, timeFrom = "semiyearly", timeUntil.AddDate(0, -6, 0)
case "yearly":
period, timeFrom = "yearly", timeUntil.AddDate(-1, 0, 0)
}
ctx.Data["DateFrom"] = timeFrom
ctx.Data["DateUntil"] = timeUntil
ctx.Data["Period"] = period
ctx.Data["PeriodText"] = ctx.Tr("repo.activity.period." + period)
canReadCode := ctx.Repo.Permission.CanRead(unit.TypeCode)
if canReadCode {
// GetActivityStats needs to read the default branch to get some information
branchExist, _ := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, ctx.Repo.Repository.DefaultBranch)
if !branchExist {
ctx.Data["NotFoundPrompt"] = ctx.Tr("repo.branch.default_branch_not_exist", ctx.Repo.Repository.DefaultBranch)
ctx.NotFound(nil)
return
}
}
var err error
// TODO: refactor these arguments to a struct
ctx.Data["Activity"], err = activities_model.GetActivityStats(ctx, ctx.Repo.Repository, timeFrom,
ctx.Repo.Permission.CanRead(unit.TypeReleases),
ctx.Repo.Permission.CanRead(unit.TypeIssues),
ctx.Repo.Permission.CanRead(unit.TypePullRequests),
canReadCode,
)
if err != nil {
ctx.ServerError("GetActivityStats", err)
return
}
if ctx.PageData["repoActivityTopAuthors"], err = activities_model.GetActivityStatsTopAuthors(ctx, ctx.Repo.Repository, timeFrom, 10); err != nil {
ctx.ServerError("GetActivityStatsTopAuthors", err)
return
}
ctx.HTML(http.StatusOK, tplActivity)
}
// ActivityAuthors renders JSON with top commit authors for given time period over all branches
func ActivityAuthors(ctx *context.Context) {
timeUntil := time.Now()
var timeFrom time.Time
switch ctx.PathParam("period") {
case "daily":
timeFrom = timeUntil.Add(-time.Hour * 24)
case "halfweekly":
timeFrom = timeUntil.Add(-time.Hour * 72)
case "weekly":
timeFrom = timeUntil.Add(-time.Hour * 168)
case "monthly":
timeFrom = timeUntil.AddDate(0, -1, 0)
case "quarterly":
timeFrom = timeUntil.AddDate(0, -3, 0)
case "semiyearly":
timeFrom = timeUntil.AddDate(0, -6, 0)
case "yearly":
timeFrom = timeUntil.AddDate(-1, 0, 0)
default:
timeFrom = timeUntil.Add(-time.Hour * 168)
}
authors, err := activities_model.GetActivityStatsTopAuthors(ctx, ctx.Repo.Repository, timeFrom, 10)
if err != nil {
ctx.ServerError("GetActivityStatsTopAuthors", err)
return
}
ctx.JSON(http.StatusOK, authors)
}