瀏覽代碼

Reser repo owner to organization when error occurs in repo create page, dashboard news feed page, create organization page

Unknwon 10 年之前
父節點
當前提交
9813161411

+ 12 - 12
cmd/web.go

@@ -104,9 +104,8 @@ func runWeb(*cli.Context) {
 	m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install)
 	m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost)
 	m.Group("", func(r *macaron.Router) {
-		r.Get("/issues", user.Issues)
 		r.Get("/pulls", user.Pulls)
-		r.Get("/stars", user.Stars)
+		r.Get("/issues", user.Issues)
 	}, reqSignIn)
 
 	// API routers.
@@ -171,13 +170,6 @@ func runWeb(*cli.Context) {
 	m.Map(cpt)
 	m.Get("/captcha/*", cpt.Handler)
 
-	m.Group("/repo", func(r *macaron.Router) {
-		r.Get("/create", repo.Create)
-		r.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost)
-		r.Get("/migrate", repo.Migrate)
-		r.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost)
-	}, reqSignIn)
-
 	adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
 
 	m.Get("/admin", adminReq, admin.Dashboard)
@@ -215,10 +207,10 @@ func runWeb(*cli.Context) {
 
 	// Organization routers.
 	m.Group("/org", func(r *macaron.Router) {
-		r.Get("/create", org.New)
-		r.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.NewPost)
+		r.Get("/create", org.Create)
+		r.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost)
 		r.Get("/:org", org.Home)
-		r.Get("/:org/dashboard", org.Dashboard)
+		r.Get("/:org/dashboard", user.Dashboard)
 		r.Get("/:org/members", org.Members)
 
 		r.Get("/:org/teams", org.Teams)
@@ -233,6 +225,14 @@ func runWeb(*cli.Context) {
 		r.Post("/:org/settings/delete", org.DeletePost)
 	}, reqSignIn)
 
+	// Repository routers.
+	m.Group("/repo", func(r *macaron.Router) {
+		r.Get("/create", repo.Create)
+		r.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost)
+		r.Get("/migrate", repo.Migrate)
+		r.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost)
+	}, reqSignIn)
+
 	m.Group("/:username/:reponame", func(r *macaron.Router) {
 		r.Get("/settings", repo.Setting)
 		r.Post("/settings", bindIgnErr(auth.RepoSettingForm{}), repo.SettingPost)

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

@@ -74,10 +74,12 @@ password_not_match = Password and re-type password are not same.
 
 username_been_taken = Username has been already taken.
 repo_name_been_taken = Repository name has been already taken.
+org_name_been_taken = Organization name has been already taken.
 email_been_used = E-mail address has been already used.
 ssh_key_been_used = Public key name has been used.
 illegal_username = Your username contains illegal characters.
 illegal_repo_name = Repository name contains illegal characters.
+illegal_org_name = Organization name contains illegal characters.
 username_password_incorrect = Username or password is not correct.
 
 invalid_ssh_key = Sorry, we're not able to verify your SSH key: %s
@@ -140,6 +142,12 @@ license_helper = Select a license file
 init_readme = Initialize this repository with a README.md
 create_repo = Create Repository
 
+[org]
+org_name_holder = Organization Name
+org_name_helper = Great organization names are short and memorable.
+org_email_helper = Organization's Email receives all notifications and confirmations.
+create_org = Create Organization
+
 [action]
 create_repo = created repository <a href="/%s">%s</a>
 commit_repo = pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>

+ 8 - 0
conf/locale/locale_zh-CN.ini

@@ -74,10 +74,12 @@ password_not_match = 密码与确认密码未匹配。
 
 username_been_taken = 用户名已经被占用。
 repo_name_been_taken = 仓库名称已经被占用。
+org_name_been_taken = 组织名称已经被占用。
 email_been_used = 邮箱地址已经被使用。
 ssh_key_been_used = SSH 密钥已经被使用。
 illegal_username = 您的用户名包含非法字符。
 illegal_repo_name = 仓库名称包含非法字符。
+illegal_org_name = 组织名称包含非法字符。
 username_password_incorrect = 用户名或密码不正确。
 
 invalid_ssh_key = 很抱歉,我们无法验证您输入的 SSH 密钥:%s
@@ -140,6 +142,12 @@ license_helper = 请选择授权许可文件
 init_readme = 使用 README.md 文件初始化仓库
 create_repo = 创建仓库
 
+[org]
+org_name_holder = 组织名称
+org_name_helper = 伟大的组织都有一个简短而寓意深刻的名字。
+org_email_helper = 组织的邮箱用于接收所有通知和确认邮件。
+create_org = 创建组织
+
 [action]
 create_repo = 创建了仓库 <a href="/%s">%s</a>
 commit_repo = 推送了 <a href="/%s/src/%s">%s</a> 分支的代码到 <a href="/%s">%s</a>

+ 3 - 5
models/action.go

@@ -305,13 +305,11 @@ func TransferRepoAction(u, newUser *User, repo *Repository) (err error) {
 }
 
 // GetFeeds returns action list of given user in given context.
-func GetFeeds(userid, offset int64, isProfile bool) ([]*Action, error) {
+func GetFeeds(uid, offset int64, isProfile bool) ([]*Action, error) {
 	actions := make([]*Action, 0, 20)
-	sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", userid)
+	sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", uid)
 	if isProfile {
-		sess.Where("is_private=?", false).And("act_user_id=?", userid)
-	} else {
-		sess.And("act_user_id!=?", userid)
+		sess.Where("is_private=?", false).And("act_user_id=?", uid)
 	}
 	err := sess.Find(&actions)
 	return actions, err

+ 16 - 16
models/repo.go

@@ -204,6 +204,22 @@ type Mirror struct {
 	NextUpdate time.Time
 }
 
+func GetMirror(repoId int64) (*Mirror, error) {
+	m := &Mirror{RepoId: repoId}
+	has, err := x.Get(m)
+	if err != nil {
+		return nil, err
+	} else if !has {
+		return nil, ErrMirrorNotExist
+	}
+	return m, nil
+}
+
+func UpdateMirror(m *Mirror) error {
+	_, err := x.Id(m.Id).Update(m)
+	return err
+}
+
 // MirrorRepository creates a mirror repository from source.
 func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
 	_, stderr, err := process.ExecTimeout(10*time.Minute,
@@ -226,22 +242,6 @@ func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) er
 	return nil
 }
 
-func GetMirror(repoId int64) (*Mirror, error) {
-	m := &Mirror{RepoId: repoId}
-	has, err := x.Get(m)
-	if err != nil {
-		return nil, err
-	} else if !has {
-		return nil, ErrMirrorNotExist
-	}
-	return m, nil
-}
-
-func UpdateMirror(m *Mirror) error {
-	_, err := x.Id(m.Id).Update(m)
-	return err
-}
-
 // MirrorUpdate checks and updates mirror repositories.
 func MirrorUpdate() {
 	if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error {

+ 1 - 1
modules/auth/org.go

@@ -19,7 +19,7 @@ import (
 //         \/     /_____/     \/     \/         \/     \/                    \/
 
 type CreateOrgForm struct {
-	OrgName string `form:"orgname" binding:"Required;AlphaDashDot;MaxSize(30)"`
+	OrgName string `form:"org_name" binding:"Required;AlphaDashDot;MaxSize(30)"`
 	Email   string `form:"email" binding:"Required;Email;MaxSize(50)"`
 }
 

+ 0 - 2
modules/middleware/context.go

@@ -220,8 +220,6 @@ func Contexter() macaron.Handler {
 			ctx.IsSigned = true
 			ctx.Data["IsSigned"] = ctx.IsSigned
 			ctx.Data["SignedUser"] = ctx.User
-			ctx.Data["SignedUserId"] = ctx.User.Id
-			ctx.Data["SignedUserName"] = ctx.User.Name
 			ctx.Data["IsAdmin"] = ctx.User.IsAdmin
 		}
 

+ 12 - 4
public/ng/css/gogs.css

@@ -265,6 +265,9 @@ img.avatar-30 {
 .markdown ul li {
   list-style: inside;
 }
+.markdown ol li {
+  list-style: decimal inside;
+}
 .markdown li {
   line-height: 1.6;
   margin-top: 6px;
@@ -346,10 +349,6 @@ img.avatar-30 {
 .markdown .btn {
   color: #fff;
 }
-.markdown .anchor-wrap {
-  /*margin-top: -50px;*/
-  /*padding-top: 50px;*/
-}
 .markdown h1 a,
 .markdown h2 a,
 .markdown h3 a {
@@ -660,40 +659,49 @@ The dashboard page style
 #dashboard-sidebar-menu > li.last > a {
   border-top-right-radius: .3em;
 }
+#dashboard-my-mirror li,
 #dashboard-my-org li,
 #dashboard-my-repo li {
   border-bottom: 1px solid #EAEAEA;
 }
+#dashboard-my-mirror li.private,
 #dashboard-my-org li.private,
 #dashboard-my-repo li.private {
   background-color: #fcf8e9;
 }
+#dashboard-my-mirror li:last-child,
 #dashboard-my-org li:last-child,
 #dashboard-my-repo li:last-child {
   border-bottom: none;
 }
+#dashboard-my-mirror li a,
 #dashboard-my-org li a,
 #dashboard-my-repo li a {
   padding: 6px 1.2em;
   display: block;
 }
+#dashboard-my-mirror li a .octicon,
 #dashboard-my-org li a .octicon,
 #dashboard-my-repo li a .octicon {
   margin-right: 6px;
   color: #888;
 }
+#dashboard-my-mirror li a:hover .repo-name,
 #dashboard-my-org li a:hover .repo-name,
 #dashboard-my-repo li a:hover .repo-name {
   text-decoration: underline;
 }
+#dashboard-my-mirror .repo-name,
 #dashboard-my-org .repo-name,
 #dashboard-my-repo .repo-name {
   font-size: 1.1em;
 }
+#dashboard-my-mirror .repo-star,
 #dashboard-my-org .repo-star,
 #dashboard-my-repo .repo-star {
   color: #888;
 }
+#dashboard-my-mirror .repo-contrib-header,
 #dashboard-my-org .repo-contrib-header,
 #dashboard-my-repo .repo-contrib-header {
   border-top: 1px solid #d6d6d6;

+ 122 - 91
public/ng/js/gogs.js

@@ -1,8 +1,11 @@
 // @codekit-prepend "lib/jquery-1.11.1.min.js"
+// @codekit-prepend "lib/lib.js"
 // @codekit-prepend "lib/tabs.js"
 
+var Gogs = {};
+
 (function ($) {
-    // extend jQuery ajax, set csrf token value
+    // Extend jQuery ajax, set CSRF token value.
     var ajax = $.ajax;
     $.extend({
         ajax: function (url, options) {
@@ -51,15 +54,131 @@
     });
 }(jQuery));
 
+(function ($) {
+    // Render markdown.
+    Gogs.renderMarkdown = function () {
+        var $md = $('.markdown');
+        var $pre = $md.find('pre > code').parent();
+        $pre.addClass('prettyprint linenums');
+        prettyPrint();
+
+        // Set anchor.
+        var headers = {};
+        $md.find('h1, h2, h3, h4, h5, h6').each(function () {
+            var node = $(this);
+            var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-'));
+            var name = val;
+            if (headers[val] > 0) {
+                name = val + '-' + headers[val];
+            }
+            if (headers[val] == undefined) {
+                headers[val] = 1;
+            } else {
+                headers[val] += 1;
+            }
+            node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
+            node.append('<a class="anchor" href="#' + name + '"><span class="octicon octicon-link"></span></a>');
+        });
+    };
+
+    // Render code view.
+    Gogs.renderCodeView = function () {
+        function selectRange($list, $select, $from) {
+            $list.removeClass('active');
+            if ($from) {
+                var a = parseInt($select.attr('rel').substr(1));
+                var b = parseInt($from.attr('rel').substr(1));
+                var c;
+                if (a != b) {
+                    if (a > b) {
+                        c = a;
+                        a = b;
+                        b = c;
+                    }
+                    var classes = [];
+                    for (i = a; i <= b; i++) {
+                        classes.push('.L' + i);
+                    }
+                    $list.filter(classes.join(',')).addClass('active');
+                    $.changeHash('#L' + a + '-' + 'L' + b);
+                    return
+                }
+            }
+            $select.addClass('active');
+            $.changeHash('#' + $select.attr('rel'));
+        }
+
+        $(document).on('click', '.lines-num span', function (e) {
+            var $select = $(this);
+            var $list = $select.parent().siblings('.lines-code').find('ol.linenums > li');
+            selectRange($list, $list.filter('[rel=' + $select.attr('rel') + ']'), (e.shiftKey ? $list.filter('.active').eq(0) : null));
+            $.deSelect();
+        });
+
+        $('.code-view .lines-code > pre').each(function () {
+            var $pre = $(this);
+            var $lineCode = $pre.parent();
+            var $lineNums = $lineCode.siblings('.lines-num');
+            if ($lineNums.length > 0) {
+                var nums = $pre.find('ol.linenums > li').length;
+                for (var i = 1; i <= nums; i++) {
+                    $lineNums.append('<span id="L' + i + '" rel="L' + i + '">' + i + '</span>');
+                }
+            }
+        });
+
+        $(window).on('hashchange', function (e) {
+            var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/);
+            var $list = $('.code-view ol.linenums > li');
+            if (m) {
+                var $first = $list.filter('.' + m[1]);
+                selectRange($list, $first, $list.filter('.' + m[2]));
+                $("html, body").scrollTop($first.offset().top - 200);
+                return;
+            }
+            m = window.location.hash.match(/^#(L\d+)$/);
+            if (m) {
+                var $first = $list.filter('.' + m[1]);
+                selectRange($list, $first);
+                $("html, body").scrollTop($first.offset().top - 200);
+            }
+        }).trigger('hashchange');
+    };
+})(jQuery);
+
+function initCore() {
+    Gogs.renderMarkdown();
+    Gogs.renderCodeView();
+}
+
+function initRepoCreate() {
+    // Owner switch menu click.
+    $('#repo-create-owner-list').on('click', 'li', function () {
+        if (!$(this).hasClass('checked')) {
+            var uid = $(this).data('uid');
+            $('#repo-owner-id').val(uid);
+            $('#repo-owner-avatar').attr("src", $(this).find('img').attr("src"));
+            $('#repo-owner-name').text($(this).text().trim());
+
+            $(this).parent().find('.checked').removeClass('checked');
+            $(this).addClass('checked');
+            console.log("set repo owner to uid :", uid, $(this).text().trim());
+        }
+    });
+}
+
 $(document).ready(function () {
+    initCore();
+    if ($('#repo-create-form').length) {
+        initRepoCreate();
+    }
+
     Tabs('#dashboard-sidebar-menu');
 
     homepage();
     settingsProfile();
     settingsSSHKeys();
     settingsDelete();
-    renderMarkdown();
-    renderCodeView();
 
     // Fix language drop-down menu height.
     var l = $('#footer-lang li').length;
@@ -114,92 +233,4 @@ function settingsDelete() {
             return true;
         }
     });
-}
-
-function renderMarkdown() {
-    var $md = $('.markdown');
-    var $pre = $md.find('pre > code').parent();
-    $pre.addClass('prettyprint linenums');
-    prettyPrint();
-
-    // Set anchor.
-    var headers = {};
-    $md.find('h1, h2, h3, h4, h5, h6').each(function () {
-        var node = $(this);
-        var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-'));
-        var name = val;
-        if (headers[val] > 0) {
-            name = val + '-' + headers[val];
-        }
-        if (headers[val] == undefined) {
-            headers[val] = 1;
-        } else {
-            headers[val] += 1;
-        }
-        node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
-        node.append('<a class="anchor" href="#' + name + '"><span class="octicon octicon-link"></span></a>');
-    });
-}
-
-function renderCodeView() {
-    function selectRange($list, $select, $from) {
-        $list.removeClass('active');
-        if ($from) {
-            var a = parseInt($select.attr('rel').substr(1));
-            var b = parseInt($from.attr('rel').substr(1));
-            var c;
-            if (a != b) {
-                if (a > b) {
-                    c = a;
-                    a = b;
-                    b = c;
-                }
-                var classes = [];
-                for (i = a; i <= b; i++) {
-                    classes.push('.L' + i);
-                }
-                $list.filter(classes.join(',')).addClass('active');
-                $.changeHash('#L' + a + '-' + 'L' + b);
-                return
-            }
-        }
-        $select.addClass('active');
-        $.changeHash('#' + $select.attr('rel'));
-    }
-
-    $(document).on('click', '.lines-num span', function (e) {
-        var $select = $(this);
-        var $list = $select.parent().siblings('.lines-code').find('ol.linenums > li');
-        selectRange($list, $list.filter('[rel=' + $select.attr('rel') + ']'), (e.shiftKey ? $list.filter('.active').eq(0) : null));
-        $.deSelect();
-    });
-
-    $('.code-view .lines-code > pre').each(function () {
-        var $pre = $(this);
-        var $lineCode = $pre.parent();
-        var $lineNums = $lineCode.siblings('.lines-num');
-        if ($lineNums.length > 0) {
-            var nums = $pre.find('ol.linenums > li').length;
-            for (var i = 1; i <= nums; i++) {
-                $lineNums.append('<span id="L' + i + '" rel="L' + i + '">' + i + '</span>');
-            }
-        }
-    });
-
-    $(window).on('hashchange', function (e) {
-        var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/);
-        var $list = $('.code-view ol.linenums > li');
-        if (m) {
-            var $first = $list.filter('.' + m[1]);
-            selectRange($list, $first, $list.filter('.' + m[2]));
-            $("html, body").scrollTop($first.offset().top - 200);
-            return;
-        }
-        m = window.location.hash.match(/^#(L\d+)$/);
-        if (m) {
-            var $first = $list.filter('.' + m[1]);
-            selectRange($list, $first);
-            $("html, body").scrollTop($first.offset().top - 200);
-        }
-    }).trigger('hashchange');
 }

文件差異過大導致無法顯示
+ 0 - 0
public/ng/js/min/gogs-min.js


+ 13 - 52
routers/org/org.go

@@ -10,12 +10,11 @@ import (
 	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/middleware"
-	"github.com/gogits/gogs/routers/user"
 )
 
 const (
 	HOME     base.TplName = "org/home"
-	NEW      base.TplName = "org/new"
+	CREATE   base.TplName = "org/create"
 	SETTINGS base.TplName = "org/settings"
 )
 
@@ -55,23 +54,23 @@ func Home(ctx *middleware.Context) {
 	ctx.HTML(200, HOME)
 }
 
-func New(ctx *middleware.Context) {
-	ctx.Data["Title"] = "Create An Organization"
-	ctx.HTML(200, NEW)
+func Create(ctx *middleware.Context) {
+	ctx.Data["Title"] = ctx.Tr("new_org")
+	ctx.HTML(200, CREATE)
 }
 
-func NewPost(ctx *middleware.Context, form auth.CreateOrgForm) {
-	ctx.Data["Title"] = "Create An Organization"
+func CreatePost(ctx *middleware.Context, form auth.CreateOrgForm) {
+	ctx.Data["Title"] = ctx.Tr("new_org")
 
 	if ctx.HasError() {
-		ctx.HTML(200, NEW)
+		ctx.HTML(200, CREATE)
 		return
 	}
 
 	org := &models.User{
 		Name:     form.OrgName,
 		Email:    form.Email,
-		IsActive: true, // NOTE: may need to set false when require e-mail confirmation.
+		IsActive: true,
 		Type:     models.ORGANIZATION,
 	}
 
@@ -80,61 +79,23 @@ func NewPost(ctx *middleware.Context, form auth.CreateOrgForm) {
 		switch err {
 		case models.ErrUserAlreadyExist:
 			ctx.Data["Err_OrgName"] = true
-			ctx.RenderWithErr("Organization name has been already taken", NEW, &form)
+			ctx.RenderWithErr(ctx.Tr("form.org_name_been_taken"), CREATE, &form)
 		case models.ErrEmailAlreadyUsed:
 			ctx.Data["Err_Email"] = true
-			ctx.RenderWithErr("E-mail address has been already used", NEW, &form)
+			ctx.RenderWithErr(ctx.Tr("form.email_been_used"), CREATE, &form)
 		case models.ErrUserNameIllegal:
 			ctx.Data["Err_OrgName"] = true
-			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), NEW, &form)
+			ctx.RenderWithErr(ctx.Tr("form.illegal_org_name"), CREATE, &form)
 		default:
-			ctx.Handle(500, "org.NewPost(CreateUser)", err)
+			ctx.Handle(500, "CreateUser", err)
 		}
 		return
 	}
-	log.Trace("%s Organization created: %s", ctx.Req.RequestURI, org.Name)
+	log.Trace("Organization created: %s", org.Name)
 
 	ctx.Redirect("/org/" + form.OrgName + "/dashboard")
 }
 
-func Dashboard(ctx *middleware.Context) {
-	ctx.Data["Title"] = "Dashboard"
-	ctx.Data["PageIsUserDashboard"] = true
-	ctx.Data["PageIsOrgDashboard"] = true
-
-	org, err := models.GetUserByName(ctx.Params(":org"))
-	if err != nil {
-		if err == models.ErrUserNotExist {
-			ctx.Handle(404, "org.Dashboard(GetUserByName)", err)
-		} else {
-			ctx.Handle(500, "org.Dashboard(GetUserByName)", err)
-		}
-		return
-	}
-
-	if err := ctx.User.GetOrganizations(); err != nil {
-		ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
-		return
-	}
-	ctx.Data["Orgs"] = ctx.User.Orgs
-	ctx.Data["ContextUser"] = org
-
-	ctx.Data["MyRepos"], err = models.GetRepositories(org.Id, true)
-	if err != nil {
-		ctx.Handle(500, "org.Dashboard(GetRepositories)", err)
-		return
-	}
-
-	actions, err := models.GetFeeds(org.Id, 0, false)
-	if err != nil {
-		ctx.Handle(500, "org.Dashboard(GetFeeds)", err)
-		return
-	}
-	ctx.Data["Feeds"] = actions
-
-	ctx.HTML(200, user.DASHBOARD)
-}
-
 func Settings(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Settings"
 

+ 19 - 33
routers/repo/repo.go

@@ -36,11 +36,10 @@ func Create(ctx *middleware.Context) {
 	ctx.Data["Licenses"] = models.Licenses
 
 	ctxUser := ctx.User
-	orgId := com.StrTo(ctx.Query("org")).MustInt64()
-	if orgId > 0 {
+	if orgId := com.StrTo(ctx.Query("org")).MustInt64(); orgId > 0 {
 		org, err := models.GetUserById(orgId)
 		if err != nil && err != models.ErrUserNotExist {
-			ctx.Handle(500, "home.Dashboard(GetUserById)", err)
+			ctx.Handle(500, "GetUserById", err)
 			return
 		}
 		ctxUser = org
@@ -48,10 +47,10 @@ func Create(ctx *middleware.Context) {
 	ctx.Data["ContextUser"] = ctxUser
 
 	if err := ctx.User.GetOrganizations(); err != nil {
-		ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+		ctx.Handle(500, "GetOrganizations", err)
 		return
 	}
-	ctx.Data["AllUsers"] = append([]*models.User{ctx.User}, ctx.User.Orgs...)
+	ctx.Data["Orgs"] = ctx.User.Orgs
 
 	ctx.HTML(200, CREATE)
 }
@@ -64,11 +63,11 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
 	ctx.Data["Licenses"] = models.Licenses
 
 	ctxUser := ctx.User
-	orgId := com.StrTo(ctx.Query("org")).MustInt64()
-	if orgId > 0 {
-		org, err := models.GetUserById(orgId)
+	// Not equal means current user is an organization.
+	if form.Uid != ctx.User.Id {
+		org, err := models.GetUserById(form.Uid)
 		if err != nil && err != models.ErrUserNotExist {
-			ctx.Handle(500, "home.Dashboard(GetUserById)", err)
+			ctx.Handle(500, "GetUserById", err)
 			return
 		}
 		ctxUser = org
@@ -76,7 +75,7 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
 	ctx.Data["ContextUser"] = ctxUser
 
 	if err := ctx.User.GetOrganizations(); err != nil {
-		ctx.Handle(500, "home.CreatePost(GetOrganizations)", err)
+		ctx.Handle(500, "GetOrganizations", err)
 		return
 	}
 	ctx.Data["Orgs"] = ctx.User.Orgs
@@ -86,32 +85,19 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
 		return
 	}
 
-	u := ctx.User
-	// Not equal means current user is an organization.
-	if u.Id != form.Uid {
-		var err error
-		u, err = models.GetUserById(form.Uid)
-		if err != nil {
-			if err == models.ErrUserNotExist {
-				ctx.Handle(404, "home.CreatePost(GetUserById)", err)
-			} else {
-				ctx.Handle(500, "home.CreatePost(GetUserById)", err)
-			}
-			return
-		}
-
+	if ctxUser.IsOrganization() {
 		// Check ownership of organization.
-		if !u.IsOrgOwner(ctx.User.Id) {
+		if !ctxUser.IsOrgOwner(ctx.User.Id) {
 			ctx.Error(403)
 			return
 		}
 	}
 
-	repo, err := models.CreateRepository(u, form.RepoName, form.Description,
+	repo, err := models.CreateRepository(ctxUser, form.RepoName, form.Description,
 		form.Gitignore, form.License, form.Private, false, form.InitReadme)
 	if err == nil {
-		log.Trace("Repository created: %s/%s", u.Name, form.RepoName)
-		ctx.Redirect("/" + u.Name + "/" + form.RepoName)
+		log.Trace("Repository created: %s/%s", ctxUser.Name, form.RepoName)
+		ctx.Redirect("/" + ctxUser.Name + "/" + form.RepoName)
 		return
 	} else if err == models.ErrRepoAlreadyExist {
 		ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), CREATE, &form)
@@ -122,7 +108,7 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
 	}
 
 	if repo != nil {
-		if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil {
+		if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
 			log.Error(4, "DeleteRepository: %v", errDelete)
 		}
 	}
@@ -134,7 +120,7 @@ func Migrate(ctx *middleware.Context) {
 	ctx.Data["PageIsNewRepo"] = true
 
 	if err := ctx.User.GetOrganizations(); err != nil {
-		ctx.Handle(500, "home.Migrate(GetOrganizations)", err)
+		ctx.Handle(500, "GetOrganizations", err)
 		return
 	}
 	ctx.Data["Orgs"] = ctx.User.Orgs
@@ -147,7 +133,7 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
 	ctx.Data["PageIsNewRepo"] = true
 
 	if err := ctx.User.GetOrganizations(); err != nil {
-		ctx.Handle(500, "home.MigratePost(GetOrganizations)", err)
+		ctx.Handle(500, "GetOrganizations", err)
 		return
 	}
 	ctx.Data["Orgs"] = ctx.User.Orgs
@@ -164,9 +150,9 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
 		u, err = models.GetUserById(form.Uid)
 		if err != nil {
 			if err == models.ErrUserNotExist {
-				ctx.Handle(404, "home.MigratePost(GetUserById)", err)
+				ctx.Handle(404, "GetUserById", err)
 			} else {
-				ctx.Handle(500, "home.MigratePost(GetUserById)", err)
+				ctx.Handle(500, "GetUserById", err)
 			}
 			return
 		}

+ 57 - 18
routers/user/home.go

@@ -17,8 +17,8 @@ import (
 
 const (
 	DASHBOARD base.TplName = "user/dashboard/dashboard"
+	PULLS     base.TplName = "user/dashboard/pulls"
 	ISSUES    base.TplName = "user/issues"
-	PULLS     base.TplName = "user/pulls"
 	STARS     base.TplName = "user/stars"
 	PROFILE   base.TplName = "user/profile"
 )
@@ -28,26 +28,59 @@ func Dashboard(ctx *middleware.Context) {
 	ctx.Data["PageIsDashboard"] = true
 	ctx.Data["PageIsNews"] = true
 
+	var ctxUser *models.User
+	// Check context type.
+	orgName := ctx.Params(":org")
+	if len(orgName) > 0 {
+		// Organization.
+		org, err := models.GetUserByName(orgName)
+		if err != nil {
+			if err == models.ErrUserNotExist {
+				ctx.Handle(404, "GetUserByName", err)
+			} else {
+				ctx.Handle(500, "GetUserByName", err)
+			}
+			return
+		}
+		ctxUser = org
+	} else {
+		// Normal user.
+		ctxUser = ctx.User
+		collaborates, err := models.GetCollaborativeRepos(ctxUser.Name)
+		if err != nil {
+			ctx.Handle(500, "GetCollaborativeRepos", err)
+			return
+		}
+		ctx.Data["CollaborateCount"] = len(collaborates)
+		ctx.Data["CollaborativeRepos"] = collaborates
+	}
+	ctx.Data["ContextUser"] = ctxUser
+
 	if err := ctx.User.GetOrganizations(); err != nil {
-		ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+		ctx.Handle(500, "GetOrganizations", err)
 		return
 	}
-	ctx.Data["ContextUser"] = ctx.User
+	ctx.Data["Orgs"] = ctx.User.Orgs
 
-	repos, err := models.GetRepositories(ctx.User.Id, true)
+	repos, err := models.GetRepositories(ctxUser.Id, true)
 	if err != nil {
 		ctx.Handle(500, "GetRepositories", err)
 		return
 	}
 	ctx.Data["Repos"] = repos
 
-	ctx.Data["CollaborativeRepos"], err = models.GetCollaborativeRepos(ctx.User.Name)
-	if err != nil {
-		ctx.Handle(500, "GetCollaborativeRepos", err)
-		return
+	// Get mirror repositories.
+	mirrors := make([]*models.Repository, 0, len(repos)/2)
+	for _, repo := range repos {
+		if repo.IsMirror {
+			mirrors = append(mirrors, repo)
+		}
 	}
+	ctx.Data["MirrorCount"] = len(mirrors)
+	ctx.Data["Mirrors"] = mirrors
 
-	actions, err := models.GetFeeds(ctx.User.Id, 0, true)
+	// Get feeds.
+	actions, err := models.GetFeeds(ctxUser.Id, 0, false)
 	if err != nil {
 		ctx.Handle(500, "GetFeeds", err)
 		return
@@ -57,7 +90,7 @@ func Dashboard(ctx *middleware.Context) {
 	feeds := make([]*models.Action, 0, len(actions))
 	for _, act := range actions {
 		if act.IsPrivate {
-			if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
+			if has, _ := models.HasAccess(ctxUser.Name, act.RepoUserName+"/"+act.RepoName,
 				models.READABLE); !has {
 				continue
 			}
@@ -68,6 +101,20 @@ func Dashboard(ctx *middleware.Context) {
 	ctx.HTML(200, DASHBOARD)
 }
 
+func Pulls(ctx *middleware.Context) {
+	ctx.Data["Title"] = ctx.Tr("pull_requests")
+	ctx.Data["PageIsDashboard"] = true
+	ctx.Data["PageIsPulls"] = true
+
+	if err := ctx.User.GetOrganizations(); err != nil {
+		ctx.Handle(500, "GetOrganizations", err)
+		return
+	}
+	ctx.Data["ContextUser"] = ctx.User
+
+	ctx.HTML(200, PULLS)
+}
+
 func Profile(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Profile"
 	ctx.Data["PageIsUserProfile"] = true
@@ -279,11 +326,3 @@ func Issues(ctx *middleware.Context) {
 	}
 	ctx.HTML(200, ISSUES)
 }
-
-func Pulls(ctx *middleware.Context) {
-	ctx.HTML(200, PULLS)
-}
-
-func Stars(ctx *middleware.Context) {
-	ctx.HTML(200, STARS)
-}

+ 1 - 0
templates/ng/base/head.tmpl

@@ -6,6 +6,7 @@
         <meta name="author" content="Gogs - Go Git Service" />
 		<meta name="description" content="Gogs(Go Git Service) a painless self-hosted Git Service written in Go" />
 		<meta name="keywords" content="go, git, self-hosted, gogs">
+		<meta name="_csrf" content="{{.CsrfToken}}" />
 
 		<link rel="shortcut icon" href="/img/favicon.png" />
 

+ 31 - 0
templates/org/create.tmpl

@@ -0,0 +1,31 @@
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+<div id="sign-wrapper">
+    <form class="form-align form panel sign-panel sign-form container panel-radius" id="sign-up-form" action="/org/create" method="post">
+        {{.CsrfTokenHtml}}
+        <div class="panel-header">
+            <h2>{{.i18n.Tr "new_org"}}</h2>
+        </div>
+        <div class="panel-content">
+            {{template "ng/base/alert" .}}
+            <p class="field">
+                <label class="req" for="org_name">{{.i18n.Tr "org.org_name_holder"}}</label>
+                <input class="ipt ipt-large ipt-radius {{if .Err_OrgName}}ipt-error{{end}}" id="org_name" name="org_name" type="text" value="{{.org_name}}" required/>
+                <label></label>
+                <span class="help">{{.i18n.Tr "org.org_name_helper"}}</span>
+            </p>
+            <p class="field">
+                <label class="req" for="email">{{.i18n.Tr "email"}}</label>
+                <input class="ipt ipt-large ipt-radius {{if .Err_Email}}ipt-error{{end}}" id="email" name="email" type="email" value="{{.email}}" required/>
+                <label></label>
+                <span class="help">{{.i18n.Tr "org.org_email_helper"}}</span>
+            </p>
+            <p class="field">
+                <span class="form-label"></span>
+                <button class="btn btn-large btn-blue btn-radius">{{.i18n.Tr "org.create_org"}}</button>
+                <a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="/"><strong>{{.i18n.Tr "cancel"}}</strong></a>
+            </p>
+        </div>
+    </form>
+</div>
+{{template "ng/base/footer" .}}

+ 7 - 7
templates/repo/create.tmpl

@@ -8,23 +8,23 @@
             {{template "ng/base/alert" .}}
             <div class="field">
                 <label for="owner" class="req">{{.i18n.Tr "repo.owner"}}</label>
-                <input id="owner" type="hidden" name="uid" value="{{.ContextUser.Id}}" />
+                <input id="repo-owner-id" type="hidden" name="uid" value="{{.ContextUser.Id}}" />
                 <div class="inline-block drop">
                     <a href="#" class="drop-bottom">
-                        <img class="avatar" src="{{.ContextUser.AvatarLink}}" alt="user-avatar">
-                        <strong>{{.ContextUser.Name}}</strong>
+                        <img class="avatar" src="{{.ContextUser.AvatarLink}}" id="repo-owner-avatar" alt="user-avatar">
+                        <strong id="repo-owner-name">{{.ContextUser.Name}}</strong>
                     </a>
                     <ul class="drop-down menu menu-vertical menu-radius switching-list" id="repo-create-owner-list">
-                        <li {{if eq $.ContextUser.Id .SignedUser.Id}}class="checked"{{end}}>
-                            <a href="#">
+                        <li {{if eq $.ContextUser.Id .SignedUser.Id}}class="checked"{{end}} data-uid="{{.SignedUser.Id}}">
+                            <a>
                                 <i class="octicon octicon-check"></i>
                                 <img class="avatar" src="{{.SignedUser.AvatarLink}}" alt="user-avatar">
                                 <strong>{{.SignedUser.Name}}</strong>
                             </a>
                         </li>
                         {{range .Orgs}}
-                        <li {{if eq $.ContextUser.Id .Id}}class="checked"{{end}}>
-                            <a href="#">
+                        <li {{if eq $.ContextUser.Id .Id}}class="checked"{{end}} data-uid="{{.Id}}">
+                            <a>
                                 <i class="octicon octicon-check"></i>
                                 <img class="avatar" src="{{.AvatarLink}}" alt="user-avatar">
                                 <strong>{{.Name}}</strong>

+ 27 - 4
templates/user/dashboard/dashboard.tmpl

@@ -73,7 +73,7 @@
                     <ul class="list-no-style">
                         {{range .Repos}}
                         <li {{if .IsPrivate}}class="private"{{end}}>
-                            <a href="{{$.ContextUser.Name}}/{{.Name}}">
+                            <a href="/{{$.ContextUser.Name}}/{{.Name}}">
                                 <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i>
                                 <span class="repo-name">
                                     <strong class="repo">{{.Name}}</strong>
@@ -88,7 +88,9 @@
                 </div>
                 {{if not .ContextUser.IsOrganization}}
                 <div class="panel-header repo-contrib-header">
-                    <h4 class="text-bold">{{.i18n.Tr "home.collaborative_repos"}}</h4>
+                    <h4 class="text-bold">{{.i18n.Tr "home.collaborative_repos"}}
+                        <span class="repo-count label label-gray label-radius">{{.CollaborateCount}}</span>
+                    </h4>
                 </div>
                 <div class="panel-body">
                     <ul class="list-no-style">
@@ -113,7 +115,9 @@
             {{if not .ContextUser.IsOrganization}}
             <div class="panel" id="dashboard-my-org">
                 <div class="panel-header">
-                    <h4 class="text-bold">{{.i18n.Tr "home.my_orgs"}}</h4>
+                    <h4 class="text-bold">{{.i18n.Tr "home.my_orgs"}}
+                        <span class="repo-count label label-gray label-radius">{{.ContextUser.GetOrganizationCount}}</span>
+                    </h4>
                 </div>
                 <div class="panel-body">
                     <ul class="list-no-style">
@@ -136,7 +140,26 @@
             {{end}}
             <div class="panel" id="dashboard-my-mirror">
                 <div class="panel-header">
-                    <h4 class="text-bold">{{.i18n.Tr "home.my_mirrors"}}</h4>
+                    <h4 class="text-bold">{{.i18n.Tr "home.my_mirrors"}}
+                        <span class="repo-count label label-gray label-radius">{{.MirrorCount}}</span>
+                    </h4>
+                </div>
+                <div class="panel-body">
+                    <ul class="list-no-style">
+                        {{range .Mirrors}}
+                        <li {{if .IsPrivate}}class="private"{{end}}>
+                            <a href="/{{$.ContextUser.Name}}/{{.Name}}">
+                                <i class="octicon octicon-repo-clone"></i>
+                                <span class="repo-name">
+                                    <strong class="repo">{{.Name}}</strong>
+                                </span>
+                                <span class="right repo-star">
+                                    <i class="octicon octicon-star"></i>{{.NumStars}}
+                                </span>
+                            </a>
+                        </li>
+                        {{end}}
+                    </ul>
                 </div>
             </div>
         </div>

+ 1 - 1
templates/user/dashboard/nav.tmpl

@@ -15,7 +15,7 @@
                             {{.SignedUser.Name}}
                         </a>
                     </li>
-                    {{range .ContextUser.Orgs}}
+                    {{range .Orgs}}
                     <li class="org {{if eq $.ContextUser.Id .Id}}checked{{end}}">
                         <a href="{{.DashboardLink}}">
                             <i class="octicon octicon-check"></i>

+ 5 - 0
templates/user/dashboard/pulls.tmpl

@@ -0,0 +1,5 @@
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+{{template "user/dashboard/nav" .}}
+
+{{template "ng/base/footer" .}}

+ 0 - 17
templates/user/pulls.tmpl

@@ -1,17 +0,0 @@
-{{template "base/head" .}}
-{{template "base/navbar" .}}
-<div id="body-nav">
-    <div class="container">
-        <ul class="nav nav-pills pull-right">
-            <li><a href="/">Feed</a></li>
-            <li><a href="/issues">Issues</a></li>
-            <li class="active"><a href="/pulls">Pull Requests</a></li>
-            <li><a href="/stars">Stars</a></li>
-        </ul>
-        <h3>Pull Requests</h3>
-    </div>
-</div>
-<div id="body" class="container" data-page="user">
-    {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
-</div>
-{{template "base/footer" .}}

+ 1 - 1
templates/user/signin.tmpl

@@ -7,7 +7,7 @@
             <h2>{{.i18n.Tr "sign_in"}}</h2>
         </div>
         <div class="panel-content">
-            {{template "base/alert" .}}
+            {{template "ng/base/alert" .}}
             <p class="field">
                 <label class="req" for="username">{{.i18n.Tr "home.uname_holder"}}</label>
                 <input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="username" name="uname" type="text" value="{{.uname}}" required/>

+ 1 - 1
templates/user/signup.tmpl

@@ -7,7 +7,7 @@
             <h2>{{.i18n.Tr "sign_up"}}</h2>
         </div>
         <div class="panel-content">
-            {{template "base/alert" .}}
+            {{template "ng/base/alert" .}}
 	        {{if .DisableRegistration}}
 	        <p>{{.i18n.Tr "auth.disable_register_prompt"}}</p>
 	        {{else}}

部分文件因文件數量過多而無法顯示