From c80d7f33b67ad1beff7378bcba3aa44ac84669e9 Mon Sep 17 00:00:00 2001
From: KN4CK3R <KN4CK3R@users.noreply.github.com>
Date: Fri, 30 Apr 2021 19:25:13 +0200
Subject: [PATCH] Unified link creation. (#15619)

---
 models/user.go                            |  7 ++++++-
 modules/context/org.go                    |  5 ++---
 routers/org/org.go                        |  2 +-
 routers/repo/issue_label.go               |  3 +--
 routers/repo/migrate.go                   |  2 +-
 routers/repo/pull.go                      |  4 ++--
 routers/repo/repo.go                      |  4 ++--
 routers/repo/setting.go                   |  6 +++---
 templates/admin/org/list.tmpl             |  2 +-
 templates/user/dashboard/navbar.tmpl      | 14 +++++++-------
 templates/user/settings/organization.tmpl |  2 +-
 11 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/models/user.go b/models/user.go
index 6665782d35..26cfc0804e 100644
--- a/models/user.go
+++ b/models/user.go
@@ -301,7 +301,7 @@ func (u *User) CanImportLocal() bool {
 // DashboardLink returns the user dashboard page link.
 func (u *User) DashboardLink() string {
 	if u.IsOrganization() {
-		return setting.AppSubURL + "/org/" + u.Name + "/dashboard/"
+		return u.OrganisationLink() + "/dashboard/"
 	}
 	return setting.AppSubURL + "/"
 }
@@ -316,6 +316,11 @@ func (u *User) HTMLURL() string {
 	return setting.AppURL + u.Name
 }
 
+// OrganisationLink returns the organization sub page link.
+func (u *User) OrganisationLink() string {
+	return setting.AppSubURL + "/org/" + u.Name
+}
+
 // GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
 func (u *User) GenerateEmailActivateCode(email string) string {
 	code := base.CreateTimeLimitCode(
diff --git a/modules/context/org.go b/modules/context/org.go
index 5148cc4a6c..527ccfbcaa 100644
--- a/modules/context/org.go
+++ b/modules/context/org.go
@@ -9,7 +9,6 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
-	"code.gitea.io/gitea/modules/setting"
 )
 
 // Organization contains organization context
@@ -70,7 +69,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 
 	// Force redirection when username is actually a user.
 	if !org.IsOrganization() {
-		ctx.Redirect(setting.AppSubURL + "/" + org.Name)
+		ctx.Redirect(org.HomeLink())
 		return
 	}
 
@@ -118,7 +117,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 	ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
 	ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo
 
-	ctx.Org.OrgLink = setting.AppSubURL + "/org/" + org.Name
+	ctx.Org.OrgLink = org.OrganisationLink()
 	ctx.Data["OrgLink"] = ctx.Org.OrgLink
 
 	// Team.
diff --git a/routers/org/org.go b/routers/org/org.go
index ef96987d42..beba3daca4 100644
--- a/routers/org/org.go
+++ b/routers/org/org.go
@@ -75,5 +75,5 @@ func CreatePost(ctx *context.Context) {
 	}
 	log.Trace("Organization created: %s", org.Name)
 
-	ctx.Redirect(setting.AppSubURL + "/org/" + form.OrgName + "/dashboard")
+	ctx.Redirect(org.DashboardLink())
 }
diff --git a/routers/repo/issue_label.go b/routers/repo/issue_label.go
index 6f862b6d0d..73612606c8 100644
--- a/routers/repo/issue_label.go
+++ b/routers/repo/issue_label.go
@@ -11,7 +11,6 @@ import (
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/log"
-	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/web"
 	"code.gitea.io/gitea/services/forms"
 	issue_service "code.gitea.io/gitea/services/issue"
@@ -88,7 +87,7 @@ func RetrieveLabels(ctx *context.Context) {
 				ctx.ServerError("org.IsOwnedBy", err)
 				return
 			}
-			ctx.Org.OrgLink = setting.AppSubURL + "/org/" + org.LowerName
+			ctx.Org.OrgLink = org.OrganisationLink()
 			ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
 			ctx.Data["OrganizationLink"] = ctx.Org.OrgLink
 		}
diff --git a/routers/repo/migrate.go b/routers/repo/migrate.go
index 231b9aedf9..24d4ef4099 100644
--- a/routers/repo/migrate.go
+++ b/routers/repo/migrate.go
@@ -234,7 +234,7 @@ func MigratePost(ctx *context.Context) {
 
 	err = task.MigrateRepository(ctx.User, ctxUser, opts)
 	if err == nil {
-		ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + opts.RepoName)
+		ctx.Redirect(ctxUser.HomeLink() + "/" + opts.RepoName)
 		return
 	}
 
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 32d11a285b..e13ad0cc03 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -201,7 +201,7 @@ func ForkPost(ctx *context.Context) {
 		}
 		repo, has := models.HasForkedRepo(ctxUser.ID, traverseParentRepo.ID)
 		if has {
-			ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
+			ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
 			return
 		}
 		if !traverseParentRepo.IsFork {
@@ -243,7 +243,7 @@ func ForkPost(ctx *context.Context) {
 	}
 
 	log.Trace("Repository forked[%d]: %s/%s", forkRepo.ID, ctxUser.Name, repo.Name)
-	ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
+	ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
 }
 
 func checkPullInfo(ctx *context.Context) *models.Issue {
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index b066fd315c..69471a83d3 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -240,7 +240,7 @@ func CreatePost(ctx *context.Context) {
 		repo, err = repo_service.GenerateRepository(ctx.User, ctxUser, templateRepo, opts)
 		if err == nil {
 			log.Trace("Repository generated [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
-			ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
+			ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
 			return
 		}
 	} else {
@@ -259,7 +259,7 @@ func CreatePost(ctx *context.Context) {
 		})
 		if err == nil {
 			log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
-			ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
+			ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
 			return
 		}
 	}
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index 533adcbdf6..b37ac03112 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -500,7 +500,7 @@ func SettingsPost(ctx *context.Context) {
 
 		log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
 		ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName()))
-		ctx.Redirect(setting.AppSubURL + "/" + ctx.Repo.Owner.Name + "/" + repo.Name + "/settings")
+		ctx.Redirect(ctx.Repo.Owner.HomeLink() + "/" + repo.Name + "/settings")
 
 	case "cancel_transfer":
 		if !ctx.Repo.IsOwner() {
@@ -512,7 +512,7 @@ func SettingsPost(ctx *context.Context) {
 		if err != nil {
 			if models.IsErrNoPendingTransfer(err) {
 				ctx.Flash.Error("repo.settings.transfer_abort_invalid")
-				ctx.Redirect(setting.AppSubURL + "/" + ctx.User.Name + "/" + repo.Name + "/settings")
+				ctx.Redirect(ctx.User.HomeLink() + "/" + repo.Name + "/settings")
 			} else {
 				ctx.ServerError("GetPendingRepositoryTransfer", err)
 			}
@@ -532,7 +532,7 @@ func SettingsPost(ctx *context.Context) {
 
 		log.Trace("Repository transfer process was cancelled: %s/%s ", ctx.Repo.Owner.Name, repo.Name)
 		ctx.Flash.Success(ctx.Tr("repo.settings.transfer_abort_success", repoTransfer.Recipient.Name))
-		ctx.Redirect(setting.AppSubURL + "/" + ctx.Repo.Owner.Name + "/" + repo.Name + "/settings")
+		ctx.Redirect(ctx.Repo.Owner.HomeLink() + "/" + repo.Name + "/settings")
 
 	case "delete":
 		if !ctx.Repo.IsOwner() {
diff --git a/templates/admin/org/list.tmpl b/templates/admin/org/list.tmpl
index e0c9ac39a7..75c4d39196 100644
--- a/templates/admin/org/list.tmpl
+++ b/templates/admin/org/list.tmpl
@@ -45,7 +45,7 @@
 							<td>{{.NumMembers}}</td>
 							<td>{{.NumRepos}}</td>
 							<td><span title="{{.CreatedUnix.FormatLong}}">{{.CreatedUnix.FormatShort}}</span></td>
-							<td><a href="{{AppSubUrl}}/org/{{.Name}}/settings">{{svg "octicon-pencil"}}</a></td>
+							<td><a href="{{.OrganisationLink}}/settings">{{svg "octicon-pencil"}}</a></td>
 						</tr>
 					{{end}}
 				</tbody>
diff --git a/templates/user/dashboard/navbar.tmpl b/templates/user/dashboard/navbar.tmpl
index 89de63d30c..6f3b4ac51c 100644
--- a/templates/user/dashboard/navbar.tmpl
+++ b/templates/user/dashboard/navbar.tmpl
@@ -23,7 +23,7 @@
 							<span class="truncated-item-name">{{.SignedUser.ShortName 40}}</span>
 						</a>
 						{{range .Orgs}}
-							<a class="{{if eq $.ContextUser.ID .ID}}active selected{{end}} item truncated-item-container" title="{{.Name}}" href="{{AppSubUrl}}/org/{{.Name}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}">
+							<a class="{{if eq $.ContextUser.ID .ID}}active selected{{end}} item truncated-item-container" title="{{.Name}}" href="{{.OrganisationLink}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}">
 								{{avatar .}}
 								<span class="truncated-item-name">{{.ShortName 40}}</span>
 								<span class="org-visibility">
@@ -58,12 +58,12 @@
 							{{.i18n.Tr "home.filter_by_team_repositories"}}
 						</div>
 						<div class="scrolling menu items">
-							<a class="{{if not $.Team}}active selected{{end}} item" title="{{.i18n.Tr "all"}}" href="{{AppSubUrl}}/org/{{$.Org.Name}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}">
+							<a class="{{if not $.Team}}active selected{{end}} item" title="{{.i18n.Tr "all"}}" href="{{$.Org.OrganisationLink}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}">
 								{{.i18n.Tr "all"}}
 							</a>
 							{{range .Org.Teams}}
 								{{if not .IncludesAllRepositories}}
-									<a class="{{if $.Team}}{{if eq $.Team.ID .ID}}active selected{{end}}{{end}} item" title="{{.Name}}" href="{{AppSubUrl}}/org/{{$.Org.Name}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}/{{.Name}}">
+									<a class="{{if $.Team}}{{if eq $.Team.ID .ID}}active selected{{end}}{{end}} item" title="{{.Name}}" href="{{$.Org.OrganisationLink}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}/{{.Name}}">
 										{{.Name}}
 									</a>
 								{{end}}
@@ -76,21 +76,21 @@
 
 	{{if .ContextUser.IsOrganization}}
 		<div class="right stackable menu">
-			<a class="{{if .PageIsNews}}active{{end}} item" style="margin-left: auto" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/dashboard{{if .Team}}/{{.Team.Name}}{{end}}">
+			<a class="{{if .PageIsNews}}active{{end}} item" style="margin-left: auto" href="{{.ContextUser.DashboardLink}}{{if .Team}}/{{.Team.Name}}{{end}}">
 				{{svg "octicon-rss"}}&nbsp;{{.i18n.Tr "activities"}}
 			</a>
 			{{if not .UnitIssuesGlobalDisabled}}
-			<a class="{{if .PageIsIssues}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/issues{{if .Team}}/{{.Team.Name}}{{end}}">
+			<a class="{{if .PageIsIssues}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/issues{{if .Team}}/{{.Team.Name}}{{end}}">
 				{{svg "octicon-issue-opened"}}&nbsp;{{.i18n.Tr "issues"}}
 			</a>
 			{{end}}
 			{{if not .UnitPullsGlobalDisabled}}
-			<a class="{{if .PageIsPulls}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/pulls{{if .Team}}/{{.Team.Name}}{{end}}">
+			<a class="{{if .PageIsPulls}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/pulls{{if .Team}}/{{.Team.Name}}{{end}}">
 				{{svg "octicon-git-pull-request"}}&nbsp;{{.i18n.Tr "pull_requests"}}
 			</a>
 			{{end}}
 			{{if and .ShowMilestonesDashboardPage (not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled))}}
-			<a class="{{if .PageIsMilestonesDashboard}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/milestones{{if .Team}}/{{.Team.Name}}{{end}}">
+			<a class="{{if .PageIsMilestonesDashboard}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/milestones{{if .Team}}/{{.Team.Name}}{{end}}">
 				{{svg "octicon-milestone"}}&nbsp;{{.i18n.Tr "milestones"}}
 			</a>
 			{{end}}
diff --git a/templates/user/settings/organization.tmpl b/templates/user/settings/organization.tmpl
index 07b56b90e8..3bab1c8957 100644
--- a/templates/user/settings/organization.tmpl
+++ b/templates/user/settings/organization.tmpl
@@ -17,7 +17,7 @@
 					{{range .Orgs}}
 					<div class="item">
 						<div class="right floated content">
-							<form method="post" action="{{AppSubUrl}}/org/{{.Name}}/members/action/leave">
+							<form method="post" action="{{.OrganisationLink}}/members/action/leave">
 								{{$.CsrfTokenHtml}}
 								<button type="submit" class="ui blue small button" name="uid" value="{{.ID}}">{{$.i18n.Tr "org.members.leave"}}</button>
 							</form>