From 566e8ecce0df27e09d9f3ed9503f788827cc1102 Mon Sep 17 00:00:00 2001
From: Jonas Franz <info@jonasfranz.software>
Date: Mon, 18 Sep 2017 16:52:20 +0200
Subject: [PATCH] Fork permission bug fixes (#2534)

* Hotfix for "Add time manually" (https://github.com/go-gitea/gitea/pull/2211#issuecomment-328780125)

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Checking if Code unit is enabled before creating a fork.

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Adding a discrete function for RepoIDAssignment

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Improved Documentation
---
 models/repo.go           |  2 +-
 modules/context/repo.go  | 68 ++++++++++++++++++++++++++++++++++++++++
 routers/routes/routes.go |  6 ++--
 3 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/models/repo.go b/models/repo.go
index 4b3b0322d6..4c844d9b56 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -638,7 +638,7 @@ func (repo *Repository) UpdateSize() error {
 
 // CanBeForked returns true if repository meets the requirements of being forked.
 func (repo *Repository) CanBeForked() bool {
-	return !repo.IsBare
+	return !repo.IsBare && repo.UnitEnabled(UnitTypeCode)
 }
 
 // CanEnablePulls returns true if repository meets the requirements of accepting pulls.
diff --git a/modules/context/repo.go b/modules/context/repo.go
index a82535a6d4..acfccfcd05 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -171,6 +171,74 @@ func RedirectToRepo(ctx *Context, redirectRepoID int64) {
 	)
 	ctx.Redirect(redirectPath)
 }
+// RepoIDAssignment returns an macaron handler which assigns the repo to the context.
+func RepoIDAssignment() macaron.Handler {
+	return func(ctx *Context) {
+		var (
+			err   error
+		)
+
+		repoID := ctx.ParamsInt64(":repoid")
+
+		// Get repository.
+		repo, err := models.GetRepositoryByID(repoID)
+		if err != nil {
+			if models.IsErrRepoNotExist(err) {
+				ctx.Handle(404, "GetRepositoryByID", nil)
+			} else {
+				ctx.Handle(500, "GetRepositoryByID", err)
+			}
+			return
+		}
+
+		if err = repo.GetOwner(); err != nil {
+			ctx.Handle(500, "GetOwner", err)
+			return
+		}
+
+		// Admin has super access.
+		if ctx.IsSigned && ctx.User.IsAdmin {
+			ctx.Repo.AccessMode = models.AccessModeOwner
+		} else {
+			var userID int64
+			if ctx.User != nil {
+				userID = ctx.User.ID
+			}
+			mode, err := models.AccessLevel(userID, repo)
+			if err != nil {
+				ctx.Handle(500, "AccessLevel", err)
+				return
+			}
+			ctx.Repo.AccessMode = mode
+		}
+
+		// Check access.
+		if ctx.Repo.AccessMode == models.AccessModeNone {
+			if ctx.Query("go-get") == "1" {
+				earlyResponseForGoGetMeta(ctx)
+				return
+			}
+			ctx.Handle(404, "no access right", err)
+			return
+		}
+		ctx.Data["HasAccess"] = true
+
+		if repo.IsMirror {
+			ctx.Repo.Mirror, err = models.GetMirrorByRepoID(repo.ID)
+			if err != nil {
+				ctx.Handle(500, "GetMirror", err)
+				return
+			}
+			ctx.Data["MirrorEnablePrune"] = ctx.Repo.Mirror.EnablePrune
+			ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
+			ctx.Data["Mirror"] = ctx.Repo.Mirror
+		}
+
+		ctx.Repo.Repository = repo
+		ctx.Data["RepoName"] = ctx.Repo.Repository.Name
+		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
+	}
+}
 
 // RepoAssignment returns a macaron to handle repository assignment
 func RepoAssignment() macaron.Handler {
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index a0684c8478..c5d6793ff3 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -419,8 +419,10 @@ func RegisterRoutes(m *macaron.Macaron) {
 		m.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost)
 		m.Get("/migrate", repo.Migrate)
 		m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost)
-		m.Combo("/fork/:repoid").Get(repo.Fork).
-			Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost)
+		m.Group("/fork", func() {
+			m.Combo("/:repoid").Get(repo.Fork).
+				Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost)
+		}, context.RepoIDAssignment(), context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeCode))
 	}, reqSignIn)
 
 	m.Group("/:username/:reponame", func() {