@@ -255,8 +255,8 @@ func runWeb(*cli.Context) { | |||
r.Post("/settings", bindIgnErr(auth.RepoSettingForm{}), repo.SettingsPost) | |||
m.Group("/settings", func(r *macaron.Router) { | |||
r.Route("/collaboration", "GET,POST", repo.SettingsCollaboration) | |||
r.Get("/hooks", repo.WebHooks) | |||
r.Get("/hooks/add", repo.WebHooksAdd) | |||
r.Get("/hooks", repo.Webhooks) | |||
r.Get("/hooks/new", repo.WebHooksAdd) | |||
r.Post("/hooks/add", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksAddPost) | |||
r.Get("/hooks/:id", repo.WebHooksEdit) | |||
r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) |
@@ -178,6 +178,9 @@ settings.confirm_delete = Confirm Deletion | |||
settings.add_collaborator = Add New Collaborator | |||
settings.add_collaborator_success = New collaborator has been added. | |||
settings.remove_collaborator_success = Collaborator has been removed. | |||
settings.add_webhook = Add Webhook | |||
settings.hooks_desc = Webhooks allow external services to be notified when certain events happen on Gogs. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>. | |||
settings.remove_hook_success = Webhook has been removed. | |||
[org] | |||
org_name_holder = Organization Name |
@@ -178,6 +178,9 @@ settings.confirm_delete = 确认删除仓库 | |||
settings.add_collaborator = 增加新的协作者 | |||
settings.add_collaborator_success = 成功添加新的协作者! | |||
settings.remove_collaborator_success = 被操作的协作者已经被收回权限! | |||
settings.add_webhook = 添加 Web 钩子 | |||
settings.hooks_desc = Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks 文档</a> 获取更多信息。 | |||
settings.remove_hook_success = Web 钩子删除成功! | |||
[org] | |||
org_name_holder = 组织名称 |
@@ -17,7 +17,7 @@ import ( | |||
"github.com/gogits/gogs/modules/setting" | |||
) | |||
const APP_VER = "0.4.7.0807 Alpha" | |||
const APP_VER = "0.4.7.0809 Alpha" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) |
@@ -214,6 +214,15 @@ img.avatar-48 { | |||
cursor: pointer; | |||
font-weight: bold; | |||
} | |||
.text-success { | |||
color: #3c763d; | |||
} | |||
.text-blue { | |||
color: #15c; | |||
} | |||
.text-red { | |||
color: #DD4B39; | |||
} | |||
.markdown { | |||
background-color: white; | |||
font-size: 16px; | |||
@@ -1297,6 +1306,10 @@ The register and sign-in page style | |||
position: relative; | |||
top: 5px; | |||
} | |||
.setting-list { | |||
width: 100%; | |||
list-style: none; | |||
} | |||
#setting-wrapper { | |||
padding-bottom: 100px; | |||
} | |||
@@ -1347,18 +1360,28 @@ The register and sign-in page style | |||
#user-profile-form .field { | |||
margin-bottom: 24px; | |||
} | |||
#repo-hooks-panel, | |||
#user-ssh-panel { | |||
margin-bottom: 20px; | |||
} | |||
#user-ssh-panel .switching-list { | |||
#repo-hooks-panel .setting-list, | |||
#user-ssh-panel .setting-list { | |||
background-color: #FFF; | |||
} | |||
#user-ssh-panel .switching-list li { | |||
#repo-hooks-panel .setting-list li, | |||
#user-ssh-panel .setting-list li { | |||
padding: 8px 20px; | |||
border-bottom: 1px solid #eaeaea; | |||
} | |||
#user-ssh-panel .switching-list li.ssh:hover { | |||
#repo-hooks-panel .setting-list li.ssh:hover, | |||
#user-ssh-panel .setting-list li.ssh:hover { | |||
background-color: #ffffEE; | |||
} | |||
#repo-hooks-panel .setting-list li i, | |||
#user-ssh-panel .setting-list li i { | |||
padding-right: 5px; | |||
} | |||
#repo-hooks-panel .active-icon, | |||
#user-ssh-panel .active-icon { | |||
width: 10px; | |||
height: 10px; | |||
@@ -1367,16 +1390,21 @@ The register and sign-in page style | |||
margin-right: 20px; | |||
margin-top: 10px; | |||
} | |||
#repo-hooks-panel .ssh-content, | |||
#user-ssh-panel .ssh-content { | |||
margin-left: 24px; | |||
} | |||
#repo-hooks-panel .ssh-content .octicon, | |||
#user-ssh-panel .ssh-content .octicon { | |||
margin-right: 4px; | |||
} | |||
#repo-hooks-panel .ssh-content .print, | |||
#user-ssh-panel .ssh-content .print, | |||
#repo-hooks-panel .ssh-content .activity, | |||
#user-ssh-panel .ssh-content .activity { | |||
color: #888; | |||
} | |||
#repo-hooks-panel .ssh-delete-btn, | |||
#user-ssh-panel .ssh-delete-btn { | |||
margin-top: 6px; | |||
} |
@@ -427,6 +427,11 @@ dt { | |||
.btn-active { | |||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset, 0 0 4px rgba(0, 0, 0, 0.15) inset; | |||
} | |||
.btn-header { | |||
margin-top: -1px; | |||
color: white; | |||
padding: 0 10px; | |||
} | |||
.btn-radius { | |||
border-radius: .25em; | |||
} |
@@ -230,4 +230,13 @@ clear: both; | |||
cursor: pointer; | |||
font-weight: bold; | |||
} | |||
} | |||
.text-success { | |||
color: #3c763d; | |||
} | |||
.text-blue { | |||
color: #15c; | |||
} | |||
.text-red { | |||
color: #DD4B39; | |||
} |
@@ -469,4 +469,8 @@ | |||
.repo-user-list-block { | |||
position: relative; | |||
top: 5px; | |||
} | |||
.setting-list { | |||
width: 100%; | |||
list-style: none; | |||
} |
@@ -51,38 +51,43 @@ | |||
} | |||
} | |||
#repo-hooks-panel, | |||
#user-ssh-panel { | |||
margin-bottom: 20px; | |||
.switching-list { | |||
background-color: #FFF; | |||
li { | |||
padding: 8px 20px; | |||
&.ssh:hover { | |||
background-color: #ffffEE; | |||
} | |||
margin-bottom: 20px; | |||
.setting-list { | |||
background-color: #FFF; | |||
li { | |||
padding: 8px 20px; | |||
border-bottom: 1px solid #eaeaea; | |||
&.ssh:hover { | |||
background-color: #ffffEE; | |||
} | |||
i { | |||
padding-right: 5px; | |||
} | |||
} | |||
} | |||
} | |||
.active-icon { | |||
width: 10px; | |||
height: 10px; | |||
border-radius: 6px; | |||
padding: 0; | |||
margin-right: 20px; | |||
margin-top: 10px; | |||
} | |||
.ssh-content { | |||
margin-left: 24px; | |||
.octicon { | |||
margin-right: 4px; | |||
.active-icon { | |||
width: 10px; | |||
height: 10px; | |||
border-radius: 6px; | |||
padding: 0; | |||
margin-right: 20px; | |||
margin-top: 10px; | |||
} | |||
.print, | |||
.activity { | |||
color: #888; | |||
.ssh-content { | |||
margin-left: 24px; | |||
.octicon { | |||
margin-right: 4px; | |||
} | |||
.print, | |||
.activity { | |||
color: #888; | |||
} | |||
} | |||
.ssh-delete-btn { | |||
margin-top: 6px; | |||
} | |||
} | |||
.ssh-delete-btn { | |||
margin-top: 6px; | |||
} | |||
} | |||
#user-ssh-add-form { |
@@ -75,6 +75,11 @@ | |||
.btn-active { | |||
box-shadow: 0 0 0 1px rgba(0, 0, 0, .1) inset, 0 0 4px rgba(0, 0, 0, .15) inset | |||
} | |||
.btn-header { | |||
margin-top: -1px; | |||
color: white; | |||
padding: 0 10px; | |||
} | |||
.btn-radius { | |||
border-radius: .25em; |
@@ -360,11 +360,11 @@ p { | |||
// truncate element | |||
.text-truncate { | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
display: inline-block; | |||
vertical-align: top; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
display: inline-block; | |||
vertical-align: top; | |||
} | |||
// code elements |
@@ -23,8 +23,8 @@ import ( | |||
const ( | |||
SETTINGS_OPTIONS base.TplName = "repo/settings/options" | |||
COLLABORATION base.TplName = "repo/settings/collaboration" | |||
HOOKS base.TplName = "repo/settings/hooks" | |||
HOOKS base.TplName = "repo/hooks" | |||
HOOK_ADD base.TplName = "repo/hook_add" | |||
HOOK_EDIT base.TplName = "repo/hook_edit" | |||
) | |||
@@ -215,69 +215,25 @@ func SettingsCollaboration(ctx *middleware.Context) { | |||
ctx.HTML(200, COLLABORATION) | |||
} | |||
func SettingsCollaborationPost(ctx *middleware.Context) { | |||
repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/") | |||
name := strings.ToLower(ctx.Query("collaborator")) | |||
if len(name) == 0 || ctx.Repo.Owner.LowerName == name { | |||
ctx.Redirect(ctx.Req.RequestURI) | |||
return | |||
} | |||
has, err := models.HasAccess(name, repoLink, models.WRITABLE) | |||
if err != nil { | |||
ctx.Handle(500, "setting.CollaborationPost(HasAccess)", err) | |||
return | |||
} else if has { | |||
ctx.Redirect(ctx.Req.RequestURI) | |||
return | |||
} | |||
u, err := models.GetUserByName(name) | |||
if err != nil { | |||
if err == models.ErrUserNotExist { | |||
ctx.Flash.Error("Given user does not exist.") | |||
ctx.Redirect(ctx.Req.RequestURI) | |||
} else { | |||
ctx.Handle(500, "setting.CollaborationPost(GetUserByName)", err) | |||
} | |||
return | |||
} | |||
if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink, | |||
Mode: models.WRITABLE}); err != nil { | |||
ctx.Handle(500, "setting.CollaborationPost(AddAccess)", err) | |||
return | |||
} | |||
if setting.Service.EnableNotifyMail { | |||
if err = mailer.SendCollaboratorMail(ctx.Render, u, ctx.User, ctx.Repo.Repository); err != nil { | |||
ctx.Handle(500, "setting.CollaborationPost(SendCollaboratorMail)", err) | |||
return | |||
} | |||
} | |||
ctx.Flash.Success("New collaborator has been added.") | |||
ctx.Redirect(ctx.Req.RequestURI) | |||
} | |||
func WebHooks(ctx *middleware.Context) { | |||
ctx.Data["IsRepoToolbarWebHooks"] = true | |||
ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhooks" | |||
func Webhooks(ctx *middleware.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.settings") | |||
ctx.Data["PageIsSettingsHooks"] = true | |||
// Delete webhook. | |||
// Delete web hook. | |||
remove := com.StrTo(ctx.Query("remove")).MustInt64() | |||
if remove > 0 { | |||
if err := models.DeleteWebhook(remove); err != nil { | |||
ctx.Handle(500, "setting.WebHooks(DeleteWebhook)", err) | |||
ctx.Handle(500, "DeleteWebhook", err) | |||
return | |||
} | |||
ctx.Flash.Success("Webhook has been removed.") | |||
ctx.Flash.Success(ctx.Tr("repo.settings.remove_hook_success")) | |||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks") | |||
return | |||
} | |||
ws, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.Id) | |||
if err != nil { | |||
ctx.Handle(500, "setting.WebHooks(GetWebhooksByRepoId)", err) | |||
ctx.Handle(500, "GetWebhooksByRepoId", err) | |||
return | |||
} | |||
@@ -1 +1 @@ | |||
0.4.7.0807 Alpha | |||
0.4.7.0809 Alpha |
@@ -1,33 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
{{template "repo/nav" .}} | |||
{{template "repo/toolbar" .}} | |||
<div id="body" class="container"> | |||
{{template "repo/setting_nav" .}} | |||
<div id="repo-setting-container" class="col-md-10"> | |||
{{template "base/alert" .}} | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Webhooks | |||
</div> | |||
<div class="panel-body"> | |||
<p>Webhooks allow external services to be notified when certain events happen on GitHub. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our Webhooks Guide.<br/> </p> | |||
<ul id="repo-hooks-list" class="list-unstyled"> | |||
{{range .Webhooks}} | |||
<li> | |||
{{if .IsActive}}<span class="pull-left status text-success"><i class="fa fa-check"></i></span>{{else}}<span class="pull-left status"><i class="fa fa-times"></i></span>{{end}} | |||
<a class="link" href="{{$.RepoLink}}/settings/hooks/{{.Id}}">{{.Url}}</a> | |||
<a href="{{$.RepoLink}}/settings/hooks?remove={{.Id}}" class="remove-hook pull-right"><i class="fa fa-times"></i></a> | |||
<a href="{{$.RepoLink}}/settings/hooks/{{.Id}}" class="edit-hook pull-right"><i class="fa fa-pencil"></i></a> | |||
</li> | |||
{{end}} | |||
</ul> | |||
</div> | |||
<div class="panel-footer"> | |||
<a href="{{.RepoLink}}/settings/hooks/add"><button class="btn btn-primary">Add Webhook</button></a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,35 @@ | |||
{{template "ng/base/head" .}} | |||
{{template "ng/base/header" .}} | |||
<div id="repo-wrapper"> | |||
{{template "repo/header" .}} | |||
<div id="setting-wrapper" class="main-wrapper"> | |||
<div id="repo-setting" class="container clear"> | |||
{{template "repo/settings/nav" .}} | |||
<div class="grid-4-5 left"> | |||
<div class="setting-content"> | |||
{{template "ng/base/alert" .}} | |||
<div id="setting-content"> | |||
<div id="repo-hooks-panel" class="panel panel-radius"> | |||
<div class="panel-header"> | |||
<a class="btn btn-small btn-black btn-header btn-radius right" href="{{.RepoLink}}/settings/hooks/new">{{.i18n.Tr "repo.settings.add_webhook"}}</a> | |||
<strong>{{.i18n.Tr "repo.settings.hooks"}}</strong> | |||
</div> | |||
<ul class="panel-body setting-list"> | |||
<li>{{.i18n.Tr "repo.settings.hooks_desc" | Str2html}}</li> | |||
{{range .Webhooks}} | |||
<li> | |||
{{if .IsActive}}<span class="left text-success"><i class="fa fa-check"></i></span>{{else}}<span class="pull-left status"><i class="fa fa-times"></i></span>{{end}} | |||
<a class="link" href="{{$.RepoLink}}/settings/hooks/{{.Id}}">{{.Url}}</a> | |||
<a href="{{$.RepoLink}}/settings/hooks?remove={{.Id}}" class="text-red right"><i class="fa fa-times"></i></a> | |||
<a href="{{$.RepoLink}}/settings/hooks/{{.Id}}" class="text-blue right"><i class="fa fa-pencil"></i></a> | |||
</li> | |||
{{end}} | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "ng/base/footer" .}} |
@@ -8,38 +8,40 @@ | |||
{{template "ng/base/alert" .}} | |||
<div id="setting-content"> | |||
<div id="user-profile-setting-content" class="panel panel-radius"> | |||
<p class="panel-header"><strong>{{.i18n.Tr "settings.public_profile"}}</strong></p> | |||
<div class="panel-header"> | |||
<strong>{{.i18n.Tr "settings.public_profile"}}</strong> | |||
</div> | |||
<form class="form form-align panel-body" id="user-profile-form" action="/user/settings" method="post"> | |||
{{.CsrfTokenHtml}} | |||
<p class="text-center panel-desc">{{.i18n.Tr "settings.profile_desc"}}</p> | |||
<p class="field"> | |||
<div class="text-center panel-desc">{{.i18n.Tr "settings.profile_desc"}}</div> | |||
<div class="field"> | |||
<label class="req" for="username">{{.i18n.Tr "username"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="username" name="uname" type="text" value="{{.SignedUser.Name}}" data-uname="{{.SignedUser.Name}}" required /> | |||
</p> | |||
<p class="field"> | |||
</div> | |||
<div class="field"> | |||
<label for="full-name">{{.i18n.Tr "settings.full_name"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_FullName}}ipt-error{{end}}" id="full-name" name="fullname" type="text" value="{{.SignedUser.FullName}}" /> | |||
</p> | |||
<p class="field"> | |||
</div> | |||
<div 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="{{.SignedUser.Email}}" required /> | |||
</p> | |||
<p class="field"> | |||
</div> | |||
<div class="field"> | |||
<label for="website">{{.i18n.Tr "settings.website"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Website}}ipt-error{{end}}" id="website" name="website" type="url" value="{{.SignedUser.Website}}" /> | |||
</p> | |||
<p class="field"> | |||
</div> | |||
<div class="field"> | |||
<label for="location">{{.i18n.Tr "settings.location"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Location}}ipt-error{{end}}" id="location" name="location" type="text" value="{{.SignedUser.Location}}" /> | |||
</p> | |||
<p class="field"> | |||
</div> | |||
<div class="field"> | |||
<label for="gravatar-email">Gravatar {{.i18n.Tr "email"}}</label> | |||
<input class="ipt ipt-large ipt-radius {{if .Err_Avatar}}ipt-error{{end}}" id="gravatar-email" name="avatar" type="text" value="{{.SignedUser.AvatarEmail}}" /> | |||
</p> | |||
<p class="field"> | |||
</div> | |||
<div class="field"> | |||
<span class="form-label"></span> | |||
<button class="btn btn-green btn-large btn-radius">{{.i18n.Tr "settings.update_profile"}}</button> | |||
</p> | |||
</div> | |||
</form> | |||
</div> | |||
</div> |
@@ -8,11 +8,11 @@ | |||
{{template "ng/base/alert" .}} | |||
<div id="user-ssh-setting-content"> | |||
<div id="user-ssh-panel" class="panel panel-radius"> | |||
<p class="panel-header"> | |||
<button class="btn btn-small btn-black btn-radius right" id="ssh-add">{{.i18n.Tr "settings.add_key"}}</button> | |||
<div class="panel-header"> | |||
<a class="btn btn-small btn-black btn-header btn-radius right" id="ssh-add">{{.i18n.Tr "settings.add_key"}}</a> | |||
<strong>{{.i18n.Tr "settings.manage_ssh_keys"}}</strong> | |||
</p> | |||
<ul class="panel-body menu menu-vertical switching-list"> | |||
</div> | |||
<ul class="panel-body setting-list"> | |||
<li>{{.i18n.Tr "settings.ssh_desc"}}</li> | |||
{{range .Keys}} | |||
<li class="ssh clear"> |