aboutsummaryrefslogtreecommitdiff
path: root/models
diff options
context:
space:
mode:
authorAnthony Wang2023-02-11 23:52:36 +0000
committerAnthony Wang2023-02-11 23:52:36 +0000
commite61e9fba59d6e6f0eb86869e07d9d52867384132 (patch)
treec6072319ab1b1429eb4132c9797ab4c6d6ffd760 /models
parent1a54d5e8970f2ff6ffe3aeaa19b3917f5e7dc9fd (diff)
parent1cb8d14bf71e0b8637c9eaa10808b4fd05139f45 (diff)
Merge remote-tracking branch 'origin/main' into forgejo-federation
Diffstat (limited to 'models')
-rw-r--r--models/activities/action.go51
-rw-r--r--models/activities/action_test.go2
-rw-r--r--models/activities/notification.go16
-rw-r--r--models/issues/comment.go33
-rw-r--r--models/issues/issue.go2
-rw-r--r--models/issues/issue_xref.go14
-rw-r--r--models/issues/pull.go12
-rw-r--r--models/issues/pull_list.go14
-rw-r--r--models/organization/org.go20
-rw-r--r--models/organization/org_test.go16
-rw-r--r--models/packages/descriptor.go8
-rw-r--r--models/packages/package.go12
-rw-r--r--models/packages/package_property.go6
-rw-r--r--models/project/project.go1
-rw-r--r--models/repo/release.go5
-rw-r--r--models/repo/repo.go2
16 files changed, 162 insertions, 52 deletions
diff --git a/models/activities/action.go b/models/activities/action.go
index 4baedbfe1..8e7492c00 100644
--- a/models/activities/action.go
+++ b/models/activities/action.go
@@ -223,6 +223,49 @@ func (a *Action) GetRepoAbsoluteLink() string {
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
}
+// GetCommentHTMLURL returns link to action comment.
+func (a *Action) GetCommentHTMLURL() string {
+ return a.getCommentHTMLURL(db.DefaultContext)
+}
+
+func (a *Action) loadComment(ctx context.Context) (err error) {
+ if a.CommentID == 0 || a.Comment != nil {
+ return nil
+ }
+ a.Comment, err = issues_model.GetCommentByID(ctx, a.CommentID)
+ return err
+}
+
+func (a *Action) getCommentHTMLURL(ctx context.Context) string {
+ if a == nil {
+ return "#"
+ }
+ _ = a.loadComment(ctx)
+ if a.Comment != nil {
+ return a.Comment.HTMLURL()
+ }
+ if len(a.GetIssueInfos()) == 0 {
+ return "#"
+ }
+ // Return link to issue
+ issueIDString := a.GetIssueInfos()[0]
+ issueID, err := strconv.ParseInt(issueIDString, 10, 64)
+ if err != nil {
+ return "#"
+ }
+
+ issue, err := issues_model.GetIssueByID(ctx, issueID)
+ if err != nil {
+ return "#"
+ }
+
+ if err = issue.LoadRepo(ctx); err != nil {
+ return "#"
+ }
+
+ return issue.HTMLURL()
+}
+
// GetCommentLink returns link to action comment.
func (a *Action) GetCommentLink() string {
return a.getCommentLink(db.DefaultContext)
@@ -232,11 +275,9 @@ func (a *Action) getCommentLink(ctx context.Context) string {
if a == nil {
return "#"
}
- if a.Comment == nil && a.CommentID != 0 {
- a.Comment, _ = issues_model.GetCommentByID(ctx, a.CommentID)
- }
+ _ = a.loadComment(ctx)
if a.Comment != nil {
- return a.Comment.HTMLURL()
+ return a.Comment.Link()
}
if len(a.GetIssueInfos()) == 0 {
return "#"
@@ -257,7 +298,7 @@ func (a *Action) getCommentLink(ctx context.Context) string {
return "#"
}
- return issue.HTMLURL()
+ return issue.Link()
}
// GetBranch returns the action's repository branch.
diff --git a/models/activities/action_test.go b/models/activities/action_test.go
index 29312bd48..f37e58f68 100644
--- a/models/activities/action_test.go
+++ b/models/activities/action_test.go
@@ -36,7 +36,7 @@ func TestAction_GetRepoLink(t *testing.T) {
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
assert.Equal(t, expected, action.GetRepoLink())
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
- assert.Equal(t, comment.HTMLURL(), action.GetCommentLink())
+ assert.Equal(t, comment.HTMLURL(), action.GetCommentHTMLURL())
}
func TestGetFeeds(t *testing.T) {
diff --git a/models/activities/notification.go b/models/activities/notification.go
index f153eb058..75276a044 100644
--- a/models/activities/notification.go
+++ b/models/activities/notification.go
@@ -459,6 +459,22 @@ func (n *Notification) HTMLURL() string {
return ""
}
+// Link formats a relative URL-string to the notification
+func (n *Notification) Link() string {
+ switch n.Source {
+ case NotificationSourceIssue, NotificationSourcePullRequest:
+ if n.Comment != nil {
+ return n.Comment.Link()
+ }
+ return n.Issue.Link()
+ case NotificationSourceCommit:
+ return n.Repository.Link() + "/commit/" + url.PathEscape(n.CommitID)
+ case NotificationSourceRepository:
+ return n.Repository.Link()
+ }
+ return ""
+}
+
// APIURL formats a URL-string to the notification
func (n *Notification) APIURL() string {
return setting.AppURL + "api/v1/notifications/threads/" + strconv.FormatInt(n.ID, 10)
diff --git a/models/issues/comment.go b/models/issues/comment.go
index 82c702a88..2eefaffd8 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -393,21 +393,40 @@ func (c *Comment) HTMLURL() string {
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
+ return c.Issue.HTMLURL() + c.hashLink()
+}
+
+// Link formats a relative URL-string to the issue-comment
+func (c *Comment) Link() string {
+ err := c.LoadIssue(db.DefaultContext)
+ if err != nil { // Silently dropping errors :unamused:
+ log.Error("LoadIssue(%d): %v", c.IssueID, err)
+ return ""
+ }
+ err = c.Issue.LoadRepo(db.DefaultContext)
+ if err != nil { // Silently dropping errors :unamused:
+ log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
+ return ""
+ }
+ return c.Issue.Link() + c.hashLink()
+}
+
+func (c *Comment) hashLink() string {
if c.Type == CommentTypeCode {
if c.ReviewID == 0 {
- return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+ return "/files#" + c.HashTag()
}
if c.Review == nil {
if err := c.LoadReview(); err != nil {
log.Warn("LoadReview(%d): %v", c.ReviewID, err)
- return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+ return "/files#" + c.HashTag()
}
}
if c.Review.Type <= ReviewTypePending {
- return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+ return "/files#" + c.HashTag()
}
}
- return fmt.Sprintf("%s#%s", c.Issue.HTMLURL(), c.HashTag())
+ return "#" + c.HashTag()
}
// APIURL formats a API-string to the issue-comment
@@ -710,8 +729,8 @@ func (c *Comment) UnsignedLine() uint64 {
return uint64(c.Line)
}
-// CodeCommentURL returns the url to a comment in code
-func (c *Comment) CodeCommentURL() string {
+// CodeCommentLink returns the url to a comment in code
+func (c *Comment) CodeCommentLink() string {
err := c.LoadIssue(db.DefaultContext)
if err != nil { // Silently dropping errors :unamused:
log.Error("LoadIssue(%d): %v", c.IssueID, err)
@@ -722,7 +741,7 @@ func (c *Comment) CodeCommentURL() string {
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
- return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+ return fmt.Sprintf("%s/files#%s", c.Issue.Link(), c.HashTag())
}
// LoadPushCommits Load push commits
diff --git a/models/issues/issue.go b/models/issues/issue.go
index 806016b57..63e153d7b 100644
--- a/models/issues/issue.go
+++ b/models/issues/issue.go
@@ -421,7 +421,7 @@ func (issue *Issue) HTMLURL() string {
return fmt.Sprintf("%s/%s/%d", issue.Repo.HTMLURL(), path, issue.Index)
}
-// Link returns the Link URL to this issue.
+// Link returns the issue's relative URL.
func (issue *Issue) Link() string {
var path string
if issue.IsPull {
diff --git a/models/issues/issue_xref.go b/models/issues/issue_xref.go
index 21ee24210..a1086f9e8 100644
--- a/models/issues/issue_xref.go
+++ b/models/issues/issue_xref.go
@@ -277,26 +277,26 @@ func CommentTypeIsRef(t CommentType) bool {
return t == CommentTypeCommentRef || t == CommentTypePullRef || t == CommentTypeIssueRef
}
-// RefCommentHTMLURL returns the HTML URL for the comment that created this reference
-func (c *Comment) RefCommentHTMLURL() string {
+// RefCommentLink returns the relative URL for the comment that created this reference
+func (c *Comment) RefCommentLink() string {
// Edge case for when the reference is inside the title or the description of the referring issue
if c.RefCommentID == 0 {
- return c.RefIssueHTMLURL()
+ return c.RefIssueLink()
}
if err := c.LoadRefComment(); err != nil { // Silently dropping errors :unamused:
log.Error("LoadRefComment(%d): %v", c.RefCommentID, err)
return ""
}
- return c.RefComment.HTMLURL()
+ return c.RefComment.Link()
}
-// RefIssueHTMLURL returns the HTML URL of the issue where this reference was created
-func (c *Comment) RefIssueHTMLURL() string {
+// RefIssueLink returns the relative URL of the issue where this reference was created
+func (c *Comment) RefIssueLink() string {
if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused:
log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err)
return ""
}
- return c.RefIssue.HTMLURL()
+ return c.RefIssue.Link()
}
// RefIssueTitle returns the title of the issue where this reference was created
diff --git a/models/issues/pull.go b/models/issues/pull.go
index 044fb5fa0..3f8b0bc7a 100644
--- a/models/issues/pull.go
+++ b/models/issues/pull.go
@@ -759,8 +759,8 @@ func GetPullRequestsByHeadBranch(ctx context.Context, headBranch string, headRep
return prs, nil
}
-// GetBaseBranchHTMLURL returns the HTML URL of the base branch
-func (pr *PullRequest) GetBaseBranchHTMLURL() string {
+// GetBaseBranchLink returns the relative URL of the base branch
+func (pr *PullRequest) GetBaseBranchLink() string {
if err := pr.LoadBaseRepo(db.DefaultContext); err != nil {
log.Error("LoadBaseRepo: %v", err)
return ""
@@ -768,11 +768,11 @@ func (pr *PullRequest) GetBaseBranchHTMLURL() string {
if pr.BaseRepo == nil {
return ""
}
- return pr.BaseRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.BaseBranch)
+ return pr.BaseRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pr.BaseBranch)
}
-// GetHeadBranchHTMLURL returns the HTML URL of the head branch
-func (pr *PullRequest) GetHeadBranchHTMLURL() string {
+// GetHeadBranchLink returns the relative URL of the head branch
+func (pr *PullRequest) GetHeadBranchLink() string {
if pr.Flow == PullRequestFlowAGit {
return ""
}
@@ -784,7 +784,7 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string {
if pr.HeadRepo == nil {
return ""
}
- return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
+ return pr.HeadRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
}
// UpdateAllowEdits update if PR can be edited from maintainers
diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go
index 007c2fd90..f4efd916c 100644
--- a/models/issues/pull_list.go
+++ b/models/issues/pull_list.go
@@ -13,6 +13,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/util"
"xorm.io/xorm"
)
@@ -175,7 +176,18 @@ func (prs PullRequestList) loadAttributes(ctx context.Context) error {
}
for _, pr := range prs {
pr.Issue = set[pr.IssueID]
- pr.Issue.PullRequest = pr // panic here means issueIDs and prs are not in sync
+ /*
+ Old code:
+ pr.Issue.PullRequest = pr // panic here means issueIDs and prs are not in sync
+
+ It's worth panic because it's almost impossible to happen under normal use.
+ But in integration testing, an asynchronous task could read a database that has been reset.
+ So returning an error would make more sense, let the caller has a choice to ignore it.
+ */
+ if pr.Issue == nil {
+ return fmt.Errorf("issues and prs may be not in sync: cannot find issue %v for pr %v: %w", pr.IssueID, pr.ID, util.ErrNotExist)
+ }
+ pr.Issue.PullRequest = pr
}
return nil
}
diff --git a/models/organization/org.go b/models/organization/org.go
index 05eaead60..852facf70 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -110,22 +110,14 @@ func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) {
return CanCreateOrgRepo(db.DefaultContext, org.ID, uid)
}
-func (org *Organization) getTeam(ctx context.Context, name string) (*Team, error) {
- return GetTeam(ctx, org.ID, name)
-}
-
// GetTeam returns named team of organization.
-func (org *Organization) GetTeam(name string) (*Team, error) {
- return org.getTeam(db.DefaultContext, name)
-}
-
-func (org *Organization) getOwnerTeam(ctx context.Context) (*Team, error) {
- return org.getTeam(ctx, OwnerTeamName)
+func (org *Organization) GetTeam(ctx context.Context, name string) (*Team, error) {
+ return GetTeam(ctx, org.ID, name)
}
// GetOwnerTeam returns owner team of organization.
-func (org *Organization) GetOwnerTeam() (*Team, error) {
- return org.getOwnerTeam(db.DefaultContext)
+func (org *Organization) GetOwnerTeam(ctx context.Context) (*Team, error) {
+ return org.GetTeam(ctx, OwnerTeamName)
}
// FindOrgTeams returns all teams of a given organization
@@ -342,7 +334,7 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
}
// GetOrgByName returns organization by given name.
-func GetOrgByName(name string) (*Organization, error) {
+func GetOrgByName(ctx context.Context, name string) (*Organization, error) {
if len(name) == 0 {
return nil, ErrOrgNotExist{0, name}
}
@@ -350,7 +342,7 @@ func GetOrgByName(name string) (*Organization, error) {
LowerName: strings.ToLower(name),
Type: user_model.UserTypeOrganization,
}
- has, err := db.GetEngine(db.DefaultContext).Get(u)
+ has, err := db.GetEngine(ctx).Get(u)
if err != nil {
return nil, err
} else if !has {
diff --git a/models/organization/org_test.go b/models/organization/org_test.go
index 0a3836592..cfa304d7b 100644
--- a/models/organization/org_test.go
+++ b/models/organization/org_test.go
@@ -61,28 +61,28 @@ func TestUser_IsOrgMember(t *testing.T) {
func TestUser_GetTeam(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
- team, err := org.GetTeam("team1")
+ team, err := org.GetTeam(db.DefaultContext, "team1")
assert.NoError(t, err)
assert.Equal(t, org.ID, team.OrgID)
assert.Equal(t, "team1", team.LowerName)
- _, err = org.GetTeam("does not exist")
+ _, err = org.GetTeam(db.DefaultContext, "does not exist")
assert.True(t, organization.IsErrTeamNotExist(err))
nonOrg := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 2})
- _, err = nonOrg.GetTeam("team")
+ _, err = nonOrg.GetTeam(db.DefaultContext, "team")
assert.True(t, organization.IsErrTeamNotExist(err))
}
func TestUser_GetOwnerTeam(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
- team, err := org.GetOwnerTeam()
+ team, err := org.GetOwnerTeam(db.DefaultContext)
assert.NoError(t, err)
assert.Equal(t, org.ID, team.OrgID)
nonOrg := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 2})
- _, err = nonOrg.GetOwnerTeam()
+ _, err = nonOrg.GetOwnerTeam(db.DefaultContext)
assert.True(t, organization.IsErrTeamNotExist(err))
}
@@ -115,15 +115,15 @@ func TestUser_GetMembers(t *testing.T) {
func TestGetOrgByName(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- org, err := organization.GetOrgByName("user3")
+ org, err := organization.GetOrgByName(db.DefaultContext, "user3")
assert.NoError(t, err)
assert.EqualValues(t, 3, org.ID)
assert.Equal(t, "user3", org.Name)
- _, err = organization.GetOrgByName("user2") // user2 is an individual
+ _, err = organization.GetOrgByName(db.DefaultContext, "user2") // user2 is an individual
assert.True(t, organization.IsErrOrgNotExist(err))
- _, err = organization.GetOrgByName("") // corner case
+ _, err = organization.GetOrgByName(db.DefaultContext, "") // corner case
assert.True(t, organization.IsErrOrgNotExist(err))
}
diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go
index 3b36ee226..f4be21e74 100644
--- a/models/packages/descriptor.go
+++ b/models/packages/descriptor.go
@@ -11,6 +11,8 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/packages/cargo"
+ "code.gitea.io/gitea/modules/packages/chef"
"code.gitea.io/gitea/modules/packages/composer"
"code.gitea.io/gitea/modules/packages/conan"
"code.gitea.io/gitea/modules/packages/conda"
@@ -63,7 +65,7 @@ type PackageFileDescriptor struct {
// PackageWebLink returns the package web link
func (pd *PackageDescriptor) PackageWebLink() string {
- return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HTMLURL(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
+ return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
}
// FullWebLink returns the package version web link
@@ -129,6 +131,10 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
var metadata interface{}
switch p.Type {
+ case TypeCargo:
+ metadata = &cargo.Metadata{}
+ case TypeChef:
+ metadata = &chef.Metadata{}
case TypeComposer:
metadata = &composer.Metadata{}
case TypeConan:
diff --git a/models/packages/package.go b/models/packages/package.go
index 0015953d8..32f30fab9 100644
--- a/models/packages/package.go
+++ b/models/packages/package.go
@@ -30,6 +30,8 @@ type Type string
// List of supported packages
const (
+ TypeCargo Type = "cargo"
+ TypeChef Type = "chef"
TypeComposer Type = "composer"
TypeConan Type = "conan"
TypeConda Type = "conda"
@@ -46,6 +48,8 @@ const (
)
var TypeList = []Type{
+ TypeCargo,
+ TypeChef,
TypeComposer,
TypeConan,
TypeConda,
@@ -64,6 +68,10 @@ var TypeList = []Type{
// Name gets the name of the package type
func (pt Type) Name() string {
switch pt {
+ case TypeCargo:
+ return "Cargo"
+ case TypeChef:
+ return "Chef"
case TypeComposer:
return "Composer"
case TypeConan:
@@ -97,6 +105,10 @@ func (pt Type) Name() string {
// SVGName gets the name of the package type svg image
func (pt Type) SVGName() string {
switch pt {
+ case TypeCargo:
+ return "gitea-cargo"
+ case TypeChef:
+ return "gitea-chef"
case TypeComposer:
return "gitea-composer"
case TypeConan:
diff --git a/models/packages/package_property.go b/models/packages/package_property.go
index 1b7f253d5..e03b12c9d 100644
--- a/models/packages/package_property.go
+++ b/models/packages/package_property.go
@@ -58,6 +58,12 @@ func GetPropertiesByName(ctx context.Context, refType PropertyType, refID int64,
return pps, db.GetEngine(ctx).Where("ref_type = ? AND ref_id = ? AND name = ?", refType, refID, name).Find(&pps)
}
+// UpdateProperty updates a property
+func UpdateProperty(ctx context.Context, pp *PackageProperty) error {
+ _, err := db.GetEngine(ctx).ID(pp.ID).Update(pp)
+ return err
+}
+
// DeleteAllProperties deletes all properties of a ref
func DeleteAllProperties(ctx context.Context, refType PropertyType, refID int64) error {
_, err := db.GetEngine(ctx).Where("ref_type = ? AND ref_id = ?", refType, refID).Delete(&PackageProperty{})
diff --git a/models/project/project.go b/models/project/project.go
index 273823ac9..9074fd0c1 100644
--- a/models/project/project.go
+++ b/models/project/project.go
@@ -116,6 +116,7 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) {
return err
}
+// Link returns the project's relative URL.
func (p *Project) Link() string {
if p.OwnerID > 0 {
err := p.LoadOwner(db.DefaultContext)
diff --git a/models/repo/release.go b/models/repo/release.go
index 08b429f5e..abf91bc4b 100644
--- a/models/repo/release.go
+++ b/models/repo/release.go
@@ -130,6 +130,11 @@ func (r *Release) HTMLURL() string {
return r.Repo.HTMLURL() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
}
+// Link the relative url for a release on the web UI. release must have attributes loaded
+func (r *Release) Link() string {
+ return r.Repo.Link() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
+}
+
// IsReleaseExist returns true if release with given tag name already exists.
func IsReleaseExist(ctx context.Context, repoID int64, tagName string) (bool, error) {
if len(tagName) == 0 {
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 01b4c961d..ccc4b8bb1 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -481,7 +481,7 @@ func (repo *Repository) RepoPath() string {
return RepoPath(repo.OwnerName, repo.Name)
}
-// Link returns the repository link
+// Link returns the repository relative url
func (repo *Repository) Link() string {
return setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name)
}