ソースを参照

repo: allow private repository to have public wiki or issues

Relates to #649 and #2157
Unknwon 8 年 前
コミット
8196430f47

+ 23 - 11
cmd/web.go

@@ -493,18 +493,15 @@ func runWeb(ctx *cli.Context) error {
 
 	m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
 	m.Group("/:username/:reponame", func() {
+		m.Get("/issues", repo.RetrieveLabels, repo.Issues)
+		m.Get("/issues/:index", repo.ViewIssue)
+
 		// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
 		// So they can apply their own enable/disable logic on routers.
 		m.Group("/issues", func() {
 			m.Combo("/new", repo.MustEnableIssues).Get(context.RepoRef(), repo.NewIssue).
 				Post(bindIgnErr(form.NewIssue{}), repo.NewIssuePost)
 
-			m.Group("/:index", func() {
-				m.Post("/label", repo.UpdateIssueLabel)
-				m.Post("/milestone", repo.UpdateIssueMilestone)
-				m.Post("/assignee", repo.UpdateIssueAssignee)
-			}, reqRepoWriter)
-
 			m.Group("/:index", func() {
 				m.Post("/title", repo.UpdateIssueTitle)
 				m.Post("/content", repo.UpdateIssueContent)
@@ -515,6 +512,24 @@ func runWeb(ctx *cli.Context) error {
 			m.Post("", repo.UpdateCommentContent)
 			m.Post("/delete", repo.DeleteComment)
 		})
+	}, ignSignIn, context.RepoAssignment(true))
+	m.Group("/:username/:reponame", func() {
+		m.Group("/wiki", func() {
+			m.Get("/?:page", repo.Wiki)
+			m.Get("/_pages", repo.WikiPages)
+		}, repo.MustEnableWiki, context.RepoRef())
+	}, ignSignIn, context.RepoAssignment(false, true))
+
+	m.Group("/:username/:reponame", func() {
+		// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
+		// So they can apply their own enable/disable logic on routers.
+		m.Group("/issues", func() {
+			m.Group("/:index", func() {
+				m.Post("/label", repo.UpdateIssueLabel)
+				m.Post("/milestone", repo.UpdateIssueMilestone)
+				m.Post("/assignee", repo.UpdateIssueAssignee)
+			}, reqRepoWriter)
+		})
 		m.Group("/labels", func() {
 			m.Post("/new", bindIgnErr(form.CreateLabel{}), repo.NewLabel)
 			m.Post("/edit", bindIgnErr(form.CreateLabel{}), repo.UpdateLabel)
@@ -580,8 +595,8 @@ func runWeb(ctx *cli.Context) error {
 	m.Group("/:username/:reponame", func() {
 		m.Group("", func() {
 			m.Get("/releases", repo.MustBeNotBare, repo.Releases)
-			m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
-			m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
+			m.Get("/pulls", repo.RetrieveLabels, repo.Pulls)
+			m.Get("/pulls/:index", repo.ViewPull)
 			m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
 			m.Get("/milestones", repo.Milestones)
 		}, context.RepoRef())
@@ -595,9 +610,6 @@ func runWeb(ctx *cli.Context) error {
 		})
 
 		m.Group("/wiki", func() {
-			m.Get("/?:page", repo.Wiki)
-			m.Get("/_pages", repo.WikiPages)
-
 			m.Group("", func() {
 				m.Combo("/_new").Get(repo.NewWiki).
 					Post(bindIgnErr(form.NewWiki{}), repo.NewWikiPost)

+ 2 - 0
conf/locale/locale_en-US.ini

@@ -690,11 +690,13 @@ settings.change_reponame_prompt = This change will affect how links relate to th
 settings.advanced_settings = Advanced Settings
 settings.wiki_desc = Enable wiki system
 settings.use_internal_wiki = Use builtin wiki
+settings.allow_public_wiki_desc = Allow public access to wiki when repository is private
 settings.use_external_wiki = Use external wiki
 settings.external_wiki_url = External Wiki URL
 settings.external_wiki_url_desc = Visitors will be redirected to URL when they click on the tab.
 settings.issues_desc = Enable issue tracker
 settings.use_internal_issue_tracker = Use builtin lightweight issue tracker
+settings.allow_public_issues_desc = Allow public access to issues when repository is private
 settings.use_external_issue_tracker = Use external issue tracker
 settings.external_tracker_url = External Issue Tracker URL
 settings.external_tracker_url_desc = Visitors will be redirected to URL when they click on the tab.

+ 1 - 1
gogs.go

@@ -16,7 +16,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.10.29.0324"
+const APP_VER = "0.10.30.0324"
 
 func init() {
 	setting.AppVer = APP_VER

+ 17 - 4
models/repo.go

@@ -173,9 +173,11 @@ type Repository struct {
 
 	// Advanced settings
 	EnableWiki            bool `xorm:"NOT NULL DEFAULT true"`
+	AllowPublicWiki       bool
 	EnableExternalWiki    bool
 	ExternalWikiURL       string
 	EnableIssues          bool `xorm:"NOT NULL DEFAULT true"`
+	AllowPublicIssues     bool
 	EnableExternalTracker bool
 	ExternalTrackerURL    string
 	ExternalTrackerFormat string
@@ -253,10 +255,21 @@ func (repo *Repository) LoadAttributes() error {
 	return repo.loadAttributes(x)
 }
 
-// MustOwner always returns a valid *User object to avoid
-// conceptually impossible error handling.
-// It creates a fake object that contains error deftail
-// when error occurs.
+// IsPartialPublic returns true if repository is public or allow public access to wiki or issues.
+func (repo *Repository) IsPartialPublic() bool {
+	return !repo.IsPrivate || repo.AllowPublicWiki || repo.AllowPublicIssues
+}
+
+func (repo *Repository) CanGuestViewWiki() bool {
+	return repo.IsPartialPublic() && repo.EnableWiki && !repo.EnableExternalWiki && repo.AllowPublicWiki
+}
+
+func (repo *Repository) CanGuestViewIssues() bool {
+	return repo.IsPartialPublic() && repo.EnableIssues && !repo.EnableExternalTracker && repo.AllowPublicIssues
+}
+
+// MustOwner always returns a valid *User object to avoid conceptually impossible error handling.
+// It creates a fake object that contains error deftail when error occurs.
 func (repo *Repository) MustOwner() *User {
 	return repo.mustOwner(x)
 }

ファイルの差分が大きいため隠しています
+ 0 - 0
modules/bindata/bindata.go


+ 52 - 22
modules/context/repo.go

@@ -126,13 +126,24 @@ func earlyResponseForGoGetMeta(ctx *Context) {
 		})))
 }
 
-func RepoAssignment() macaron.Handler {
+// [0]: issues, [1]: wiki
+func RepoAssignment(pages ...bool) macaron.Handler {
 	return func(ctx *Context) {
 		var (
-			owner *models.User
-			err   error
+			owner        *models.User
+			err          error
+			isIssuesPage bool
+			isWikiPage   bool
 		)
 
+		if len(pages) > 0 {
+			isIssuesPage = pages[0]
+		}
+		if len(pages) > 1 {
+			isWikiPage = pages[1]
+		}
+		_, _ = isIssuesPage, isWikiPage
+
 		ownerName := ctx.Params(":username")
 		repoName := strings.TrimSuffix(ctx.Params(":reponame"), ".git")
 		refName := ctx.Params(":branchname")
@@ -174,20 +185,20 @@ func RepoAssignment() macaron.Handler {
 				ctx.Handle(500, "GetRepositoryByName", err)
 			}
 			return
-		} else if err = repo.GetOwner(); err != nil {
-			ctx.Handle(500, "GetOwner", err)
-			return
 		}
 
+		ctx.Repo.Repository = repo
+		ctx.Data["RepoName"] = ctx.Repo.Repository.Name
+		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
+		ctx.Repo.RepoLink = repo.Link()
+		ctx.Data["RepoLink"] = ctx.Repo.RepoLink
+		ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
+
 		// Admin has super access.
 		if ctx.IsSigned && ctx.User.IsAdmin {
 			ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
 		} else {
-			var userID int64
-			if ctx.IsSigned {
-				userID = ctx.User.ID
-			}
-			mode, err := models.AccessLevel(userID, repo)
+			mode, err := models.AccessLevel(ctx.UserID(), repo)
 			if err != nil {
 				ctx.Handle(500, "AccessLevel", err)
 				return
@@ -195,16 +206,40 @@ func RepoAssignment() macaron.Handler {
 			ctx.Repo.AccessMode = mode
 		}
 
-		// Check access.
+		// Check access
 		if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
 			if ctx.Query("go-get") == "1" {
 				earlyResponseForGoGetMeta(ctx)
 				return
 			}
-			ctx.NotFound()
-			return
+
+			// Redirect to any accessible page if not yet on it
+			if repo.IsPartialPublic() &&
+				(!(isIssuesPage || isWikiPage) ||
+					(isIssuesPage && !repo.CanGuestViewIssues()) ||
+					(isWikiPage && !repo.CanGuestViewWiki())) {
+				switch {
+				case repo.CanGuestViewIssues():
+					ctx.Redirect(repo.Link() + "/issues")
+				case repo.CanGuestViewWiki():
+					ctx.Redirect(repo.Link() + "/wiki")
+				default:
+					ctx.NotFound()
+				}
+				return
+			}
+
+			// Response 404 if user is on completely private repository or possible accessible page but owner doesn't enabled
+			if !repo.IsPartialPublic() ||
+				(isIssuesPage && !repo.CanGuestViewIssues()) ||
+				(isWikiPage && !repo.CanGuestViewWiki()) {
+				ctx.NotFound()
+				return
+			}
+
+			ctx.Repo.Repository.EnableIssues = repo.CanGuestViewIssues()
+			ctx.Repo.Repository.EnableWiki = repo.CanGuestViewWiki()
 		}
-		ctx.Data["HasAccess"] = true
 
 		if repo.IsMirror {
 			ctx.Repo.Mirror, err = models.GetMirrorByRepoID(repo.ID)
@@ -217,19 +252,12 @@ func RepoAssignment() macaron.Handler {
 			ctx.Data["Mirror"] = ctx.Repo.Mirror
 		}
 
-		ctx.Repo.Repository = repo
-		ctx.Data["RepoName"] = ctx.Repo.Repository.Name
-		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
-
 		gitRepo, err := git.OpenRepository(models.RepoPath(ownerName, repoName))
 		if err != nil {
 			ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(ownerName, repoName), err)
 			return
 		}
 		ctx.Repo.GitRepo = gitRepo
-		ctx.Repo.RepoLink = repo.Link()
-		ctx.Data["RepoLink"] = ctx.Repo.RepoLink
-		ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
 
 		tags, err := ctx.Repo.GitRepo.GetTags()
 		if err != nil {
@@ -288,6 +316,8 @@ func RepoAssignment() macaron.Handler {
 			ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
 			ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
 		}
+
+		ctx.Data["IsGuest"] = !ctx.Repo.HasAccess()
 	}
 }
 

+ 2 - 0
modules/form/repo.go

@@ -92,9 +92,11 @@ type RepoSetting struct {
 
 	// Advanced settings
 	EnableWiki            bool
+	AllowPublicWiki       bool
 	EnableExternalWiki    bool
 	ExternalWikiURL       string
 	EnableIssues          bool
+	AllowPublicIssues     bool
 	EnableExternalTracker bool
 	ExternalTrackerURL    string
 	TrackerURLFormat      string

+ 3 - 0
public/css/gogs.css

@@ -2321,6 +2321,9 @@ footer .ui.language .menu {
 .repository.wiki.view > .markdown h6:first-of-type {
   margin-top: 0;
 }
+.repository.settings.options .box.field {
+  padding-left: 27px;
+}
 .repository.settings.collaboration .collaborator.list {
   padding: 0;
 }

+ 3 - 6
public/js/gogs.js

@@ -265,11 +265,8 @@ function initRepository() {
             }
         });
         $('.enable-system-radio').change(function () {
-            if (this.value == 'false') {
-                $($(this).data('target')).addClass('disabled');
-            } else if (this.value == 'true') {
-                $($(this).data('target')).removeClass('disabled');
-            }
+			$($(this).data('enable')).removeClass('disabled');
+			$($(this).data('disable')).addClass('disabled');
         });
     }
 
@@ -1289,7 +1286,7 @@ $(document).ready(function () {
                 $this.data('url', url);
                 $this.removeClass('disabled');
             } else {
-                $this.remove(); 
+                $this.remove();
             }
         });
     });

+ 6 - 0
public/less/_repository.less

@@ -1325,6 +1325,12 @@
 	}
 
 	&.settings {
+		&.options {
+			.box.field {
+				padding-left: 27px;
+			}
+		}
+
 		&.collaboration {
 			.collaborator.list {
 				padding: 0;

+ 34 - 12
routers/repo/issue.go

@@ -89,8 +89,7 @@ func RetrieveLabels(ctx *context.Context) {
 	ctx.Data["NumLabels"] = len(labels)
 }
 
-func Issues(ctx *context.Context) {
-	isPullList := ctx.Params(":type") == "pulls"
+func issues(ctx *context.Context, isPullList bool) {
 	if isPullList {
 		MustAllowPulls(ctx)
 		if ctx.Written() {
@@ -247,6 +246,14 @@ func Issues(ctx *context.Context) {
 	ctx.HTML(200, ISSUES)
 }
 
+func Issues(ctx *context.Context) {
+	issues(ctx, false)
+}
+
+func Pulls(ctx *context.Context) {
+	issues(ctx, true)
+}
+
 func renderAttachmentSettings(ctx *context.Context) {
 	ctx.Data["RequireDropzone"] = true
 	ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled
@@ -492,7 +499,7 @@ func UploadIssueAttachment(ctx *context.Context) {
 	uploadAttachment(ctx, strings.Split(setting.AttachmentAllowedTypes, ","))
 }
 
-func ViewIssue(ctx *context.Context) {
+func viewIssue(ctx *context.Context, isPullList bool) {
 	ctx.Data["RequireHighlightJS"] = true
 	ctx.Data["RequireDropzone"] = true
 	renderAttachmentSettings(ctx)
@@ -511,10 +518,10 @@ func ViewIssue(ctx *context.Context) {
 	ctx.Data["Title"] = issue.Title
 
 	// Make sure type and URL matches.
-	if ctx.Params(":type") == "issues" && issue.IsPull {
+	if !isPullList && issue.IsPull {
 		ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
 		return
-	} else if ctx.Params(":type") == "pulls" && !issue.IsPull {
+	} else if isPullList && !issue.IsPull {
 		ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index))
 		return
 	}
@@ -652,12 +659,27 @@ func ViewIssue(ctx *context.Context) {
 	ctx.HTML(200, ISSUE_VIEW)
 }
 
+func ViewIssue(ctx *context.Context) {
+	viewIssue(ctx, false)
+}
+
+func ViewPull(ctx *context.Context) {
+	viewIssue(ctx, true)
+}
+
 func getActionIssue(ctx *context.Context) *models.Issue {
 	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
 	if err != nil {
 		ctx.NotFoundOrServerError("GetIssueByIndex", errors.IsIssueNotExist, err)
 		return nil
 	}
+
+	// Prevent guests accessing pull requests
+	if !ctx.Repo.HasAccess() && issue.IsPull {
+		ctx.NotFound()
+		return nil
+	}
+
 	return issue
 }
 
@@ -803,9 +825,8 @@ func UpdateIssueAssignee(ctx *context.Context) {
 }
 
 func NewComment(ctx *context.Context, f form.CreateComment) {
-	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
-	if err != nil {
-		ctx.NotFoundOrServerError("GetIssueByIndex", errors.IsIssueNotExist, err)
+	issue := getActionIssue(ctx)
+	if ctx.Written() {
 		return
 	}
 
@@ -820,6 +841,7 @@ func NewComment(ctx *context.Context, f form.CreateComment) {
 		return
 	}
 
+	var err error
 	var comment *models.Comment
 	defer func() {
 		// Check if issue admin/poster changes the status of issue.
@@ -895,8 +917,8 @@ func UpdateCommentContent(ctx *context.Context) {
 		return
 	}
 
-	if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
-		ctx.Error(403)
+	if ctx.UserID() != comment.PosterID && !ctx.Repo.IsAdmin() {
+		ctx.Error(404)
 		return
 	} else if comment.Type != models.COMMENT_TYPE_COMMENT {
 		ctx.Error(204)
@@ -928,8 +950,8 @@ func DeleteComment(ctx *context.Context) {
 		return
 	}
 
-	if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
-		ctx.Error(403)
+	if ctx.UserID() != comment.PosterID && !ctx.Repo.IsAdmin() {
+		ctx.Error(404)
 		return
 	} else if comment.Type != models.COMMENT_TYPE_COMMENT {
 		ctx.Error(204)

+ 2 - 0
routers/repo/setting.go

@@ -138,9 +138,11 @@ func SettingsPost(ctx *context.Context, f form.RepoSetting) {
 
 	case "advanced":
 		repo.EnableWiki = f.EnableWiki
+		repo.AllowPublicWiki = f.AllowPublicWiki
 		repo.EnableExternalWiki = f.EnableExternalWiki
 		repo.ExternalWikiURL = f.ExternalWikiURL
 		repo.EnableIssues = f.EnableIssues
+		repo.AllowPublicIssues = f.AllowPublicIssues
 		repo.EnableExternalTracker = f.EnableExternalTracker
 		repo.ExternalTrackerURL = f.ExternalTrackerURL
 		repo.ExternalTrackerFormat = f.TrackerURLFormat

+ 1 - 1
templates/.VERSION

@@ -1 +1 @@
-0.10.29.0324
+0.10.30.0324

+ 32 - 28
templates/repo/header.tmpl

@@ -13,34 +13,36 @@
 						{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{SubStr .BaseRepo.RelLink 1 -1}}</a></div>{{end}}
 					</div>
 
-					<div class="ui right">
-						<div class="ui labeled button" tabindex="0">
-							<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}">
-								<i class="icon fa-eye{{if not $.IsWatchingRepo}}-slash{{end}}"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}}
-							</a>
-							<a class="ui basic label" href="{{.Link}}/watchers">
-								{{.NumWatches}}
-							</a>
-						</div>
-						<div class="ui labeled button" tabindex="0">
-							<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}">
-								<i class="icon fa-star{{if not $.IsStaringRepo}}-o{{end}}"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}}
-							</a>
-							<a class="ui basic label" href="{{.Link}}/stars">
-								{{.NumStars}}
-							</a>
-						</div>
-						{{if .CanBeForked}}
+					{{if not $.IsGuest}}
+						<div class="ui right">
 							<div class="ui labeled button" tabindex="0">
-								<a class="ui basic button {{if eq .OwnerID $.SignedUserID}}poping up{{end}}" href="{{AppSubUrl}}/repo/fork/{{.ID}}">
-									<i class="octicon octicon-repo-forked"></i>{{$.i18n.Tr "repo.fork"}}
+								<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}">
+									<i class="icon fa-eye{{if not $.IsWatchingRepo}}-slash{{end}}"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}}
 								</a>
-								<a class="ui basic label" href="{{.Link}}/forks">
-									{{.NumForks}}
+								<a class="ui basic label" href="{{.Link}}/watchers">
+									{{.NumWatches}}
 								</a>
 							</div>
-						{{end}}
-					</div>
+							<div class="ui labeled button" tabindex="0">
+								<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}">
+									<i class="icon fa-star{{if not $.IsStaringRepo}}-o{{end}}"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}}
+								</a>
+								<a class="ui basic label" href="{{.Link}}/stars">
+									{{.NumStars}}
+								</a>
+							</div>
+							{{if .CanBeForked}}
+								<div class="ui labeled button" tabindex="0">
+									<a class="ui basic button {{if eq .OwnerID $.SignedUserID}}poping up{{end}}" href="{{AppSubUrl}}/repo/fork/{{.ID}}">
+										<i class="octicon octicon-repo-forked"></i>{{$.i18n.Tr "repo.fork"}}
+									</a>
+									<a class="ui basic label" href="{{.Link}}/forks">
+										{{.NumForks}}
+									</a>
+								</div>
+							{{end}}
+						</div>
+					{{end}}
 				</div>
 			</div><!-- end column -->
 		</div><!-- end grid -->
@@ -49,15 +51,17 @@
 {{if not .IsDiffCompare}}
 	<div class="ui tabs container">
 		<div class="ui tabular menu navbar">
-			<a class="{{if .PageIsViewFiles}}active{{end}} item" href="{{.RepoLink}}">
-				<i class="octicon octicon-file-text"></i> {{.i18n.Tr "repo.files"}}
-			</a>
+			{{if not $.IsGuest}}
+				<a class="{{if .PageIsViewFiles}}active{{end}} item" href="{{.RepoLink}}">
+					<i class="octicon octicon-file-text"></i> {{.i18n.Tr "repo.files"}}
+				</a>
+			{{end}}
 			{{if .Repository.EnableIssues}}
 				<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
 					<i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} {{if not .Repository.EnableExternalTracker}}<span class="ui {{if not .Repository.NumOpenIssues}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenIssues}}{{end}}</span>
 				</a>
 			{{end}}
-			{{if .Repository.AllowsPulls}}
+			{{if and .Repository.AllowsPulls (not .IsGuest)}}
 				<a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls">
 					<i class="octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.pulls"}} <span class="ui {{if not .Repository.NumOpenPulls}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenPulls}}</span>
 				</a>

+ 26 - 13
templates/repo/settings/options.tmpl

@@ -15,7 +15,7 @@
 						<input type="hidden" name="action" value="update">
 						<div class="required field {{if .Err_RepoName}}error{{end}}">
 							<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}<span class="text red hide" id="repo-name-change-prompt"> {{.i18n.Tr "repo.settings.change_reponame_prompt"}}</span></label>
-							<input id="repo_name" name="repo_name" value="{{.Repository.Name}}" data-repo-name="{{.Repository.Name}}" autofocus required>
+							<input id="repo_name" name="repo_name" value="{{.Repository.Name}}" data-repo-name="{{.Repository.Name}}" required>
 						</div>
 						<div class="field {{if .Err_Description}}error{{end}}">
 							<label for="description">{{$.i18n.Tr "repo.repo_desc"}}</label>
@@ -96,6 +96,7 @@
 						{{.CsrfTokenHtml}}
 						<input type="hidden" name="action" value="advanced">
 
+						<!-- Wiki -->
 						<div class="inline field">
 							<label>{{.i18n.Tr "repo.wiki"}}</label>
 							<div class="ui checkbox">
@@ -103,28 +104,34 @@
 								<label>{{.i18n.Tr "repo.settings.wiki_desc"}}</label>
 							</div>
 						</div>
-						<div class="field {{if not .Repository.EnableWiki}}disabled{{end}}" id="wiki_box">
+						<div class="ui segment field {{if not .Repository.EnableWiki}}disabled{{end}}" id="wiki_box">
 							<div class="field">
 								<div class="ui radio checkbox">
-									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not .Repository.EnableExternalWiki}}checked{{end}}/>
+									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="false" data-enable="#internal_wiki_box" data-disable="#external_wiki_box" {{if not .Repository.EnableExternalWiki}}checked{{end}}/>
 									<label>{{.i18n.Tr "repo.settings.use_internal_wiki"}}</label>
 								</div>
 							</div>
+							<div class="box field {{if .Repository.EnableExternalWiki}}disabled{{end}}" id="internal_wiki_box">
+								<div class="ui checkbox">
+									<input name="allow_public_wiki" type="checkbox" {{if .Repository.AllowPublicWiki}}checked{{end}}>
+									<label>{{.i18n.Tr "repo.settings.allow_public_wiki_desc"}}</label>
+								</div>
+							</div>
+
 							<div class="field">
 								<div class="ui radio checkbox">
-									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.EnableExternalWiki}}checked{{end}}/>
+									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="true" data-enable="#external_wiki_box" data-disable="#internal_wiki_box" {{if .Repository.EnableExternalWiki}}checked{{end}}/>
 									<label>{{.i18n.Tr "repo.settings.use_external_wiki"}}</label>
 								</div>
 							</div>
-							<div class="field {{if not .Repository.EnableExternalWiki}}disabled{{end}}" id="external_wiki_box">
+							<div class="box field {{if not .Repository.EnableExternalWiki}}disabled{{end}}" id="external_wiki_box">
 								<label for="external_wiki_url">{{.i18n.Tr "repo.settings.external_wiki_url"}}</label>
 								<input id="external_wiki_url" name="external_wiki_url" type="url" value="{{.Repository.ExternalWikiURL}}">
 								<p class="help">{{.i18n.Tr "repo.settings.external_wiki_url_desc"}}</p>
 							</div>
 						</div>
 
-						<div class="ui divider"></div>
-
+						<!-- Issues -->
 						<div class="inline field">
 							<label>{{.i18n.Tr "repo.issues"}}</label>
 							<div class="ui checkbox">
@@ -132,20 +139,27 @@
 								<label>{{.i18n.Tr "repo.settings.issues_desc"}}</label>
 							</div>
 						</div>
-						<div class="field {{if not .Repository.EnableIssues}}disabled{{end}}" id="issue_box">
+						<div class="ui segment field {{if not .Repository.EnableIssues}}disabled{{end}}" id="issue_box">
 							<div class="field">
 								<div class="ui radio checkbox">
-									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="false" data-target="#external_issue_box" {{if not .Repository.EnableExternalTracker}}checked{{end}}/>
+									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="false" data-enable="#internal_issue_box" data-disable="#external_issue_box" {{if not .Repository.EnableExternalTracker}}checked{{end}}/>
 									<label>{{.i18n.Tr "repo.settings.use_internal_issue_tracker"}}</label>
 								</div>
 							</div>
+							<div class="box field {{if .Repository.EnableExternalTracker}}disabled{{end}}" id="internal_issue_box">
+								<div class="ui checkbox">
+									<input name="allow_public_issues" type="checkbox" {{if .Repository.AllowPublicIssues}}checked{{end}}>
+									<label>{{.i18n.Tr "repo.settings.allow_public_issues_desc"}}</label>
+								</div>
+							</div>
+
 							<div class="field">
 								<div class="ui radio checkbox">
-									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="true" data-target="#external_issue_box" {{if .Repository.EnableExternalTracker}}checked{{end}}/>
+									<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="true" data-enable="#external_issue_box" data-disable="#internal_issue_box" {{if .Repository.EnableExternalTracker}}checked{{end}}/>
 									<label>{{.i18n.Tr "repo.settings.use_external_issue_tracker"}}</label>
 								</div>
 							</div>
-							<div class="field {{if not .Repository.EnableExternalTracker}}disabled{{end}}" id="external_issue_box">
+							<div class="box field {{if not .Repository.EnableExternalTracker}}disabled{{end}}" id="external_issue_box">
 								<div class="field">
 									<label for="external_tracker_url">{{.i18n.Tr "repo.settings.external_tracker_url"}}</label>
 									<input id="external_tracker_url" name="external_tracker_url" type="url" value="{{.Repository.ExternalTrackerURL}}">
@@ -174,9 +188,8 @@
 							</div>
 						</div>
 
+						<!-- Pull Requests -->
 						{{if .Repository.CanEnablePulls}}
-							<div class="ui divider"></div>
-
 							<div class="inline field">
 								<label>{{.i18n.Tr "repo.pulls"}}</label>
 								<div class="ui checkbox">

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません