| @@ -1,27 +1,19 @@ | |||||
| Copyright (c) 2014 | |||||
| All rights reserved. | |||||
| Copyright (c) 2014 All Gogs Contributors | |||||
| Redistribution and use in source and binary forms, with or without | |||||
| modification, are permitted provided that the following conditions are met: | |||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| of this software and associated documentation files (the "Software"), to deal | |||||
| in the Software without restriction, including without limitation the rights | |||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| copies of the Software, and to permit persons to whom the Software is | |||||
| furnished to do so, subject to the following conditions: | |||||
| * Redistributions of source code must retain the above copyright notice, this | |||||
| list of conditions and the following disclaimer. | |||||
| The above copyright notice and this permission notice shall be included in | |||||
| all copies or substantial portions of the Software. | |||||
| * Redistributions in binary form must reproduce the above copyright notice, | |||||
| this list of conditions and the following disclaimer in the documentation | |||||
| and/or other materials provided with the distribution. | |||||
| * Neither the name of the {organization} nor the names of its | |||||
| contributors may be used to endorse or promote products derived from | |||||
| this software without specific prior written permission. | |||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||
| THE SOFTWARE. | |||||
| @@ -5,7 +5,7 @@ Gogs(Go Git Service) is a painless self-hosted Git Service written in Go. | |||||
|  |  | ||||
| ##### Current version: 0.5.6 Beta | |||||
| ##### Current version: 0.5.7 Beta | |||||
| ### NOTICES | ### NOTICES | ||||
| @@ -35,7 +35,7 @@ The goal of this project is to make the easiest, fastest and most painless way t | |||||
| - Reverse proxy suburl support | - Reverse proxy suburl support | ||||
| - Register/delete/rename account | - Register/delete/rename account | ||||
| - Create/manage/delete organization with team management | - Create/manage/delete organization with team management | ||||
| - Create/migrate/mirror/delete/watch/rename/transfer public/private repository | |||||
| - Create/fork/migrate/mirror/delete/watch/rename/transfer public/private repository | |||||
| - Repository viewer/release/issue tracker | - Repository viewer/release/issue tracker | ||||
| - Repository and Organization level webhooks | - Repository and Organization level webhooks | ||||
| - Repository Git hooks | - Repository Git hooks | ||||
| @@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。 | |||||
|  |  | ||||
| ##### 当前版本:0.5.6 Beta | |||||
| ##### 当前版本:0.5.7 Beta | |||||
| ## 开发目的 | ## 开发目的 | ||||
| @@ -26,7 +26,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自 | |||||
| - 支持反向代理子路径 | - 支持反向代理子路径 | ||||
| - 支持 注册/删除/重命名 用户 | - 支持 注册/删除/重命名 用户 | ||||
| - 支持 创建/管理/删除 组织以及团队管理功能 | - 支持 创建/管理/删除 组织以及团队管理功能 | ||||
| - 支持 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库 | |||||
| - 支持 创建/派生/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库 | |||||
| - 支持仓库 浏览/发布/工单管理 | - 支持仓库 浏览/发布/工单管理 | ||||
| - 支持仓库和组织级别 Web 钩子 | - 支持仓库和组织级别 Web 钩子 | ||||
| - 支持仓库 Git 钩子 | - 支持仓库 Git 钩子 | ||||
| @@ -265,7 +265,7 @@ func runWeb(*cli.Context) { | |||||
| reqTrueOwner := middleware.RequireTrueOwner() | reqTrueOwner := middleware.RequireTrueOwner() | ||||
| // Organization routers. | |||||
| // Organization. | |||||
| m.Group("/org", func() { | m.Group("/org", func() { | ||||
| m.Get("/create", org.Create) | m.Get("/create", org.Create) | ||||
| m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost) | m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost) | ||||
| @@ -309,12 +309,14 @@ func runWeb(*cli.Context) { | |||||
| m.Get("/:org", org.Home) | m.Get("/:org", org.Home) | ||||
| }, middleware.OrgAssignment(true)) | }, middleware.OrgAssignment(true)) | ||||
| // Repository routers. | |||||
| // Repository. | |||||
| m.Group("/repo", func() { | m.Group("/repo", func() { | ||||
| m.Get("/create", repo.Create) | m.Get("/create", repo.Create) | ||||
| m.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost) | m.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost) | ||||
| m.Get("/migrate", repo.Migrate) | m.Get("/migrate", repo.Migrate) | ||||
| m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost) | m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost) | ||||
| m.Get("/fork", repo.Fork) | |||||
| m.Post("/fork", bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost) | |||||
| }, reqSignIn) | }, reqSignIn) | ||||
| m.Group("/:username/:reponame", func() { | m.Group("/:username/:reponame", func() { | ||||
| @@ -26,6 +26,7 @@ organization = Organization | |||||
| mirror = Mirror | mirror = Mirror | ||||
| new_repo = New Repository | new_repo = New Repository | ||||
| new_migrate = New Migration | new_migrate = New Migration | ||||
| new_fork = New Fork Repository | |||||
| new_org = New Organization | new_org = New Organization | ||||
| manage_org = Manage Organizations | manage_org = Manage Organizations | ||||
| admin_panel = Admin Panel | admin_panel = Admin Panel | ||||
| @@ -233,6 +234,9 @@ repo_name = Repository Name | |||||
| repo_name_helper = Great repository names are short, memorable and <strong>unique</strong>. | repo_name_helper = Great repository names are short, memorable and <strong>unique</strong>. | ||||
| visibility = Visibility | visibility = Visibility | ||||
| visiblity_helper = This repository is <span class="label label-red label-radius">Private</span> | visiblity_helper = This repository is <span class="label label-red label-radius">Private</span> | ||||
| fork_repo = Fork Repository | |||||
| fork_from = Fork From | |||||
| fork_visiblity_helper = Forked repository cannot change its visiblity | |||||
| repo_desc = Description | repo_desc = Description | ||||
| repo_lang = Language | repo_lang = Language | ||||
| repo_lang_helper = Select a .gitignore file | repo_lang_helper = Select a .gitignore file | ||||
| @@ -17,7 +17,7 @@ import ( | |||||
| "github.com/gogits/gogs/modules/setting" | "github.com/gogits/gogs/modules/setting" | ||||
| ) | ) | ||||
| const APP_VER = "0.5.6.1104 Beta" | |||||
| const APP_VER = "0.5.7.1105 Beta" | |||||
| func init() { | func init() { | ||||
| runtime.GOMAXPROCS(runtime.NumCPU()) | runtime.GOMAXPROCS(runtime.NumCPU()) | ||||
| @@ -1298,8 +1298,8 @@ func IsStaring(uid, repoId int64) bool { | |||||
| // \___ / \____/|__| |__|_ \ | // \___ / \____/|__| |__|_ \ | ||||
| // \/ \/ | // \/ \/ | ||||
| func ForkRepository(u *User, oldRepo *Repository) (*Repository, error) { | |||||
| isExist, err := IsRepositoryExist(u, oldRepo.Name) | |||||
| func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repository, error) { | |||||
| isExist, err := IsRepositoryExist(u, name) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } else if isExist { | } else if isExist { | ||||
| @@ -1323,9 +1323,9 @@ func ForkRepository(u *User, oldRepo *Repository) (*Repository, error) { | |||||
| repo := &Repository{ | repo := &Repository{ | ||||
| OwnerId: u.Id, | OwnerId: u.Id, | ||||
| Owner: u, | Owner: u, | ||||
| Name: oldRepo.Name, | |||||
| LowerName: oldRepo.LowerName, | |||||
| Description: oldRepo.Description, | |||||
| Name: name, | |||||
| LowerName: strings.ToLower(name), | |||||
| Description: desc, | |||||
| IsPrivate: oldRepo.IsPrivate, | IsPrivate: oldRepo.IsPrivate, | ||||
| IsFork: true, | IsFork: true, | ||||
| ForkId: oldRepo.Id, | ForkId: oldRepo.Id, | ||||
| @@ -24,8 +24,23 @@ import ( | |||||
| const ( | const ( | ||||
| CREATE base.TplName = "repo/create" | CREATE base.TplName = "repo/create" | ||||
| MIGRATE base.TplName = "repo/migrate" | MIGRATE base.TplName = "repo/migrate" | ||||
| FORK base.TplName = "repo/fork" | |||||
| ) | ) | ||||
| func checkContextUser(ctx *middleware.Context, uid int64) (*models.User, error) { | |||||
| ctxUser := ctx.User | |||||
| if uid > 0 { | |||||
| org, err := models.GetUserById(uid) | |||||
| if err != models.ErrUserNotExist { | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("GetUserById: %v", err) | |||||
| } | |||||
| ctxUser = org | |||||
| } | |||||
| } | |||||
| return ctxUser, nil | |||||
| } | |||||
| func Create(ctx *middleware.Context) { | func Create(ctx *middleware.Context) { | ||||
| ctx.Data["Title"] = ctx.Tr("new_repo") | ctx.Data["Title"] = ctx.Tr("new_repo") | ||||
| @@ -35,14 +50,10 @@ func Create(ctx *middleware.Context) { | |||||
| ctx.Data["Gitignores"] = models.Gitignores | ctx.Data["Gitignores"] = models.Gitignores | ||||
| ctx.Data["Licenses"] = models.Licenses | ctx.Data["Licenses"] = models.Licenses | ||||
| ctxUser := ctx.User | |||||
| if orgId := com.StrTo(ctx.Query("org")).MustInt64(); orgId > 0 { | |||||
| org, err := models.GetUserById(orgId) | |||||
| if err != nil && err != models.ErrUserNotExist { | |||||
| ctx.Handle(500, "GetUserById", err) | |||||
| return | |||||
| } | |||||
| ctxUser = org | |||||
| ctxUser, err := checkContextUser(ctx, ctx.QueryInt64("org")) | |||||
| if err != nil { | |||||
| ctx.Handle(500, "checkContextUser", err) | |||||
| return | |||||
| } | } | ||||
| ctx.Data["ContextUser"] = ctxUser | ctx.Data["ContextUser"] = ctxUser | ||||
| @@ -64,12 +75,12 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||||
| ctxUser := ctx.User | ctxUser := ctx.User | ||||
| // Not equal means current user is an organization. | // Not equal means current user is an organization. | ||||
| if form.Uid != ctx.User.Id { | if form.Uid != ctx.User.Id { | ||||
| org, err := models.GetUserById(form.Uid) | |||||
| if err != nil && err != models.ErrUserNotExist { | |||||
| ctx.Handle(500, "GetUserById", err) | |||||
| var err error | |||||
| ctxUser, err = checkContextUser(ctx, form.Uid) | |||||
| if err != nil { | |||||
| ctx.Handle(500, "checkContextUser", err) | |||||
| return | return | ||||
| } | } | ||||
| ctxUser = org | |||||
| } | } | ||||
| ctx.Data["ContextUser"] = ctxUser | ctx.Data["ContextUser"] = ctxUser | ||||
| @@ -95,8 +106,8 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||||
| repo, err := models.CreateRepository(ctxUser, form.RepoName, form.Description, | repo, err := models.CreateRepository(ctxUser, form.RepoName, form.Description, | ||||
| form.Gitignore, form.License, form.Private, false, form.InitReadme) | form.Gitignore, form.License, form.Private, false, form.InitReadme) | ||||
| if err == nil { | if err == nil { | ||||
| log.Trace("Repository created: %s/%s", ctxUser.Name, form.RepoName) | |||||
| ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName) | |||||
| log.Trace("Repository created: %s/%s", ctxUser.Name, repo.Name) | |||||
| ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | |||||
| return | return | ||||
| } else if err == models.ErrRepoAlreadyExist { | } else if err == models.ErrRepoAlreadyExist { | ||||
| ctx.Data["Err_RepoName"] = true | ctx.Data["Err_RepoName"] = true | ||||
| @@ -119,14 +130,10 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||||
| func Migrate(ctx *middleware.Context) { | func Migrate(ctx *middleware.Context) { | ||||
| ctx.Data["Title"] = ctx.Tr("new_migrate") | ctx.Data["Title"] = ctx.Tr("new_migrate") | ||||
| ctxUser := ctx.User | |||||
| if orgId := com.StrTo(ctx.Query("org")).MustInt64(); orgId > 0 { | |||||
| org, err := models.GetUserById(orgId) | |||||
| if err != nil && err != models.ErrUserNotExist { | |||||
| ctx.Handle(500, "GetUserById", err) | |||||
| return | |||||
| } | |||||
| ctxUser = org | |||||
| ctxUser, err := checkContextUser(ctx, ctx.QueryInt64("org")) | |||||
| if err != nil { | |||||
| ctx.Handle(500, "checkContextUser", err) | |||||
| return | |||||
| } | } | ||||
| ctx.Data["ContextUser"] = ctxUser | ctx.Data["ContextUser"] = ctxUser | ||||
| @@ -145,12 +152,12 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||||
| ctxUser := ctx.User | ctxUser := ctx.User | ||||
| // Not equal means current user is an organization. | // Not equal means current user is an organization. | ||||
| if form.Uid != ctx.User.Id { | if form.Uid != ctx.User.Id { | ||||
| org, err := models.GetUserById(form.Uid) | |||||
| var err error | |||||
| ctxUser, err = checkContextUser(ctx, form.Uid) | |||||
| if err != nil { | if err != nil { | ||||
| ctx.Handle(500, "GetUserById", err) | |||||
| ctx.Handle(500, "checkContextUser", err) | |||||
| return | return | ||||
| } | } | ||||
| ctxUser = org | |||||
| } | } | ||||
| ctx.Data["ContextUser"] = ctxUser | ctx.Data["ContextUser"] = ctxUser | ||||
| @@ -206,6 +213,114 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||||
| ctx.Handle(500, "MigratePost", err) | ctx.Handle(500, "MigratePost", err) | ||||
| } | } | ||||
| func getForkRepository(ctx *middleware.Context) (*models.Repository, error) { | |||||
| forkId := ctx.QueryInt64("fork_id") | |||||
| ctx.Data["ForkId"] = forkId | |||||
| forkRepo, err := models.GetRepositoryById(forkId) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("GetRepositoryById: %v", err) | |||||
| } | |||||
| ctx.Data["repo_name"] = forkRepo.Name | |||||
| ctx.Data["desc"] = forkRepo.Description | |||||
| if err = forkRepo.GetOwner(); err != nil { | |||||
| return nil, fmt.Errorf("GetOwner: %v", err) | |||||
| } | |||||
| ctx.Data["ForkFrom"] = forkRepo.Owner.Name + "/" + forkRepo.Name | |||||
| return forkRepo, nil | |||||
| } | |||||
| func Fork(ctx *middleware.Context) { | |||||
| ctx.Data["Title"] = ctx.Tr("new_fork") | |||||
| if _, err := getForkRepository(ctx); err != nil { | |||||
| if err == models.ErrRepoNotExist { | |||||
| ctx.Redirect(setting.AppSubUrl + "/") | |||||
| } else { | |||||
| ctx.Handle(500, "getForkRepository", err) | |||||
| } | |||||
| return | |||||
| } | |||||
| // FIXME: maybe sometime can directly fork to organization? | |||||
| ctx.Data["ContextUser"] = ctx.User | |||||
| if err := ctx.User.GetOrganizations(); err != nil { | |||||
| ctx.Handle(500, "GetOrganizations", err) | |||||
| return | |||||
| } | |||||
| ctx.Data["Orgs"] = ctx.User.Orgs | |||||
| ctx.HTML(200, FORK) | |||||
| } | |||||
| func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||||
| ctx.Data["Title"] = ctx.Tr("new_fork") | |||||
| forkRepo, err := getForkRepository(ctx) | |||||
| if err != nil { | |||||
| if err == models.ErrRepoNotExist { | |||||
| ctx.Redirect(setting.AppSubUrl + "/") | |||||
| } else { | |||||
| ctx.Handle(500, "getForkRepository", err) | |||||
| } | |||||
| return | |||||
| } | |||||
| ctxUser := ctx.User | |||||
| // Not equal means current user is an organization. | |||||
| if form.Uid != ctx.User.Id { | |||||
| var err error | |||||
| ctxUser, err = checkContextUser(ctx, form.Uid) | |||||
| if err != nil { | |||||
| ctx.Handle(500, "checkContextUser", err) | |||||
| return | |||||
| } | |||||
| } | |||||
| ctx.Data["ContextUser"] = ctxUser | |||||
| if err := ctx.User.GetOrganizations(); err != nil { | |||||
| ctx.Handle(500, "GetOrganizations", err) | |||||
| return | |||||
| } | |||||
| ctx.Data["Orgs"] = ctx.User.Orgs | |||||
| if ctx.HasError() { | |||||
| ctx.HTML(200, CREATE) | |||||
| return | |||||
| } | |||||
| if ctxUser.IsOrganization() { | |||||
| // Check ownership of organization. | |||||
| if !ctxUser.IsOrgOwner(ctx.User.Id) { | |||||
| ctx.Error(403) | |||||
| return | |||||
| } | |||||
| } | |||||
| repo, err := models.ForkRepository(ctxUser, forkRepo, form.RepoName, form.Description) | |||||
| if err == nil { | |||||
| log.Trace("Repository forked: %s/%s", ctxUser.Name, repo.Name) | |||||
| ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | |||||
| return | |||||
| } else if err == models.ErrRepoAlreadyExist { | |||||
| ctx.Data["Err_RepoName"] = true | |||||
| ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), FORK, &form) | |||||
| return | |||||
| } else if err == models.ErrRepoNameIllegal { | |||||
| ctx.Data["Err_RepoName"] = true | |||||
| ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), CREATE, &form) | |||||
| return | |||||
| } | |||||
| if repo != nil { | |||||
| if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil { | |||||
| log.Error(4, "DeleteRepository: %v", errDelete) | |||||
| } | |||||
| } | |||||
| ctx.Handle(500, "ForkPost", err) | |||||
| } | |||||
| func Action(ctx *middleware.Context) { | func Action(ctx *middleware.Context) { | ||||
| var err error | var err error | ||||
| switch ctx.Params(":action") { | switch ctx.Params(":action") { | ||||
| @@ -217,20 +332,6 @@ func Action(ctx *middleware.Context) { | |||||
| err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, true) | err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, true) | ||||
| case "unstar": | case "unstar": | ||||
| err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, false) | err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, false) | ||||
| case "fork": | |||||
| repo, err := models.ForkRepository(ctx.User, ctx.Repo.Repository) | |||||
| if err != nil { | |||||
| if err != models.ErrRepoAlreadyExist { | |||||
| log.Error(4, "Action(%s): %v", ctx.Params(":action"), err) | |||||
| ctx.JSON(200, map[string]interface{}{ | |||||
| "ok": false, | |||||
| "err": err.Error(), | |||||
| }) | |||||
| return | |||||
| } | |||||
| } | |||||
| ctx.Redirect(setting.AppSubUrl + "/" + repo.Owner.Name + "/" + repo.Name) | |||||
| return | |||||
| case "desc": | case "desc": | ||||
| if !ctx.Repo.IsOwner { | if !ctx.Repo.IsOwner { | ||||
| ctx.Error(404) | ctx.Error(404) | ||||
| @@ -1 +1 @@ | |||||
| 0.5.6.1104 Beta | |||||
| 0.5.7.1105 Beta | |||||
| @@ -0,0 +1,65 @@ | |||||
| {{template "ng/base/head" .}} | |||||
| {{template "ng/base/header" .}} | |||||
| <div id="repo-wrapper"> | |||||
| <form id="repo-create-form" class="form form-align panel panel-radius" action="{{AppSubUrl}}/repo/fork?fork_id={{.ForkId}}" method="post"> | |||||
| {{.CsrfTokenHtml}} | |||||
| <div class="panel-header"> | |||||
| <h2>{{.i18n.Tr "new_fork"}}</h2> | |||||
| </div> | |||||
| <div class="panel-content"> | |||||
| {{template "ng/base/alert" .}} | |||||
| <div class="field"> | |||||
| <label for="owner" class="req">{{.i18n.Tr "repo.owner"}}</label> | |||||
| <input id="repo-owner-id" type="hidden" name="uid" value="{{.ContextUser.Id}}" /> | |||||
| <div class="inline-block drop"> | |||||
| <a class="drop-bottom"> | |||||
| <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}} 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}} data-uid="{{.Id}}"> | |||||
| <a> | |||||
| <i class="octicon octicon-check"></i> | |||||
| <img class="avatar" src="{{.AvatarLink}}" alt="user-avatar"> | |||||
| <strong>{{.Name}}</strong> | |||||
| </a> | |||||
| </li> | |||||
| {{end}} | |||||
| </ul> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label>{{.i18n.Tr "repo.fork_from"}}</label> | |||||
| <span><a target="_blank" href="{{AppSubUrl}}/{{.ForkFrom}}">{{.ForkFrom}}</a></span> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label class="req" for="repo-name">{{.i18n.Tr "repo.repo_name"}}</label> | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_RepoName}}ipt-error{{end}}" id="repo-name" name="repo_name" type="text" value="{{.repo_name}}" required /> | |||||
| <span class="form-label"></span> | |||||
| <span class="help">{{.i18n.Tr "repo.repo_name_helper" | Str2html}}</span> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label for="visibility">{{.i18n.Tr "repo.visibility"}}</label> | |||||
| <span>{{.i18n.Tr "repo.fork_visiblity_helper"}}</span> | |||||
| </div> | |||||
| <div class="field clear"> | |||||
| <label class="left" for="desc">{{.i18n.Tr "repo.repo_desc"}}</label> | |||||
| <textarea class="ipt ipt-large ipt-radius {{if .Err_Description}}ipt-error{{end}}" id="desc" name="desc">{{.desc}}</textarea> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label></label> | |||||
| <button class="btn btn-large btn-blue btn-radius">{{.i18n.Tr "repo.fork_repo"}}</button> | |||||
| <a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="{{AppSubUrl}}/"><strong>{{.i18n.Tr "cancel"}}</strong></a> | |||||
| </div> | |||||
| </div> | |||||
| </form> | |||||
| </div> | |||||
| {{template "ng/base/footer" .}} | |||||
| @@ -47,7 +47,7 @@ | |||||
| </a> | </a> | ||||
| </li> | </li> | ||||
| <li id="repo-header-fork"> | <li id="repo-header-fork"> | ||||
| <a id="repo-header-fork-btn" {{if not $.IsRepositoryTrueOwner}}href="{{.RepoLink}}/action/fork"{{end}}> | |||||
| <a id="repo-header-fork-btn" {{if or (not $.IsRepositoryTrueOwner) $.Owner.IsOrganization}}href="/repo/fork?fork_id={{.Id}}"{{end}}> | |||||
| <button class="btn btn-gray text-bold btn-radius"> | <button class="btn btn-gray text-bold btn-radius"> | ||||
| <i class="octicon octicon-repo-forked"></i>{{$.i18n.Tr "repo.fork"}} | <i class="octicon octicon-repo-forked"></i>{{$.i18n.Tr "repo.fork"}} | ||||
| <span class="num">{{.NumForks}}</span> | <span class="num">{{.NumForks}}</span> | ||||