mirror of
1
Fork 0

Merge branch 'dev' into newcollaboration

This commit is contained in:
Peter Smit 2015-02-05 11:08:10 +02:00
commit 03af37554e
47 changed files with 1297 additions and 359 deletions

View File

@ -3,5 +3,13 @@ language: go
go: go:
- 1.2 - 1.2
- 1.3 - 1.3
- 1.4
- tip
sudo: false sudo: false
script: go build -v
notifications:
email:
- u@gogs.io

View File

@ -1,18 +1,19 @@
Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0bc450ac6f09bc56b9640a50aa/s/ "wercker status")](https://app.wercker.com/project/bykey/ad0bdb0bc450ac6f09bc56b9640a50aa) [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs)
===================== =====================
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Gogs(Go Git Service) is a painless self-hosted Git Service written in Go. Gogs(Go Git Service) is a painless self-hosted Git Service written in Go.
![Demo](https://gowalker.org/public/gogs_demo.gif) ![Demo](http://gogs.qiniudn.com/gogs_demo.gif)
##### Current version: 0.5.11 Beta ##### Current version: 0.5.12 Beta
### NOTICES ### NOTICES
- Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) has been reset in **June 21, 2014** and will reset multiple times after. Please do **NOT** put your important data on the site. - Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) has been reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
- Demo site [try.gogs.io](https://try.gogs.io) is running under `dev` branch. - Demo site [try.gogs.io](https://try.gogs.io) is running under `dev` branch.
- If you think there are vulnerabilities in the project, please talk private to **u@gogs.io**, thanks!
#### Other language version #### Other language version
@ -50,7 +51,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
- Drone CI integration - Drone CI integration
- Supports MySQL, PostgreSQL and SQLite3 - Supports MySQL, PostgreSQL and SQLite3
- Social account login(GitHub, Google, QQ, Weibo) - Social account login(GitHub, Google, QQ, Weibo)
- Multi-language support([7 languages](https://crowdin.com/project/gogs)) - Multi-language support([9 languages](https://crowdin.com/project/gogs))
## System Requirements ## System Requirements

View File

@ -3,9 +3,9 @@ Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0b
Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。 Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。
![Demo](https://gowalker.org/public/gogs_demo.gif) ![Demo](http://gogs.qiniudn.com/gogs_demo.gif)
##### 当前版本0.5.11 Beta ##### 当前版本0.5.12 Beta
## 开发目的 ## 开发目的
@ -39,7 +39,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- Drone CI 持续部署集成 - Drone CI 持续部署集成
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库 - 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
- 社交帐号登录GitHub、Google、QQ、微博 - 社交帐号登录GitHub、Google、QQ、微博
- 多语言支持([7 种语言]([more](https://crowdin.com/project/gogs)) - 多语言支持([9 种语言]([more](https://crowdin.com/project/gogs))
## 系统要求 ## 系统要求

View File

@ -164,7 +164,7 @@ func runFixLocation(ctx *cli.Context) {
fmt.Scanln() fmt.Scanln()
// Fix in authorized_keys file. // Fix in authorized_keys file.
sshPath := path.Join(models.SshPath, "authorized_keys") sshPath := path.Join(models.SSHPath, "authorized_keys")
if com.IsFile(sshPath) { if com.IsFile(sshPath) {
fmt.Printf("Fixing pathes in file: %s\n", sshPath) fmt.Printf("Fixing pathes in file: %s\n", sshPath)
if err := rewriteAuthorizedKeys(sshPath, oldPath, execPath); err != nil { if err := rewriteAuthorizedKeys(sshPath, oldPath, execPath); err != nil {

View File

@ -53,7 +53,9 @@ var CmdWeb = cli.Command{
Description: `Gogs web server is the only thing you need to run, Description: `Gogs web server is the only thing you need to run,
and it takes care of all the other things for you`, and it takes care of all the other things for you`,
Action: runWeb, Action: runWeb,
Flags: []cli.Flag{}, Flags: []cli.Flag{
cli.StringFlag{"port, p", "3000", "Temporary port number to prevent conflict", ""},
},
} }
type VerChecker struct { type VerChecker struct {
@ -75,13 +77,13 @@ func checkVersion() {
// Check dependency version. // Check dependency version.
checkers := []VerChecker{ checkers := []VerChecker{
{"github.com/Unknwon/macaron", macaron.Version, "0.5.0"}, {"github.com/Unknwon/macaron", macaron.Version, "0.5.1"},
{"github.com/macaron-contrib/binding", binding.Version, "0.0.4"}, {"github.com/macaron-contrib/binding", binding.Version, "0.0.4"},
{"github.com/macaron-contrib/cache", cache.Version, "0.0.7"}, {"github.com/macaron-contrib/cache", cache.Version, "0.0.7"},
{"github.com/macaron-contrib/csrf", csrf.Version, "0.0.1"}, {"github.com/macaron-contrib/csrf", csrf.Version, "0.0.3"},
{"github.com/macaron-contrib/i18n", i18n.Version, "0.0.5"}, {"github.com/macaron-contrib/i18n", i18n.Version, "0.0.5"},
{"github.com/macaron-contrib/session", session.Version, "0.1.6"}, {"github.com/macaron-contrib/session", session.Version, "0.1.6"},
{"gopkg.in/ini.v1", ini.Version, "1.0.1"}, {"gopkg.in/ini.v1", ini.Version, "1.2.0"},
} }
for _, c := range checkers { for _, c := range checkers {
ver := strings.Join(strings.Split(c.Version(), ".")[:3], ".") ver := strings.Join(strings.Split(c.Version(), ".")[:3], ".")
@ -162,7 +164,7 @@ func newMacaron() *macaron.Macaron {
return m return m
} }
func runWeb(*cli.Context) { func runWeb(ctx *cli.Context) {
routers.GlobalInit() routers.GlobalInit()
checkVersion() checkVersion()
@ -179,9 +181,9 @@ func runWeb(*cli.Context) {
// Routers. // Routers.
m.Get("/", ignSignIn, routers.Home) m.Get("/", ignSignIn, routers.Home)
m.Get("/explore", ignSignIn, routers.Explore) m.Get("/explore", ignSignIn, routers.Explore)
// FIXME: when i'm binding form here??? m.Combo("/install", routers.InstallInit).
m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install) Get(routers.Install).
m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost) Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)
m.Group("", func() { m.Group("", func() {
m.Get("/pulls", user.Pulls) m.Get("/pulls", user.Pulls)
m.Get("/issues", user.Issues) m.Get("/issues", user.Issues)
@ -460,6 +462,12 @@ func runWeb(*cli.Context) {
// Not found handler. // Not found handler.
m.NotFound(routers.NotFound) m.NotFound(routers.NotFound)
// Flag for port number in case first time run conflict.
if ctx.IsSet("port") {
setting.AppUrl = strings.Replace(setting.AppUrl, setting.HttpPort, ctx.String("port"), 1)
setting.HttpPort = ctx.String("port")
}
var err error var err error
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort) listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl) log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl)

View File

@ -1,3 +1,6 @@
# NEVER EVER MODIFY THIS FILE
# PLEASE MAKE CHANGES ON CORRESPONDING CUSTOM CONFIG FILE
; App name that shows on every page title ; App name that shows on every page title
APP_NAME = Gogs: Go Git Service APP_NAME = Gogs: Go Git Service
; Change it if you run locally ; Change it if you run locally
@ -275,5 +278,5 @@ INTERVAL = 24
ARGS = ARGS =
[i18n] [i18n]
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL,lv-LV,ru-RU LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL,lv-LV,ru-RU,ja-JP
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский,日本语

View File

@ -1,6 +1,9 @@
# This file lists all PUBLIC individuals having contributed content to the translation. # This file lists all PUBLIC individuals having contributed content to the translation.
# Order of name is meaningless. # Order of name is meaningless.
Akihiro YAGASAKI <yaggytter@momiage.com>
Christoph Kisfeld <christoph.kisfeld@gmail.com>
Thomas Fanninger <gogs.thomas@fanninger.at> Thomas Fanninger <gogs.thomas@fanninger.at>
Łukasz Jan Niemier <lukasz@niemier.pl> Łukasz Jan Niemier <lukasz@niemier.pl>
Lafriks <lafriks@gmail.com> Lafriks <lafriks@gmail.com>
Miguel de la Cruz <miguel@mcrx.me>

View File

@ -59,12 +59,14 @@ run_user = Run User
run_user_helper = The user must have access to Repository Root Path and run Gogs. run_user_helper = The user must have access to Repository Root Path and run Gogs.
domain = Domain domain = Domain
domain_helper = This affects SSH clone URLs. domain_helper = This affects SSH clone URLs.
http_port = HTTP Port
http_port_helper = Port number which application will listen on.
app_url = Application URL app_url = Application URL
app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in e-mail. app_url_helper = This affects HTTP/HTTPS clone URL and somewhere in e-mail.
email_title = E-mail Service Settings (Optional) email_title = E-mail Service Settings (Optional)
smtp_host = SMTP Host smtp_host = SMTP Host
mailer_user = Sender E-mail mailer_user = Sender E-mail
mailer_password = Sender Password mailer_password = Sender Password
notify_title = Notification Settings(Optional) notify_title = Notification Settings(Optional)
register_confirm = Enable Register Confirmation register_confirm = Enable Register Confirmation
mail_notify = Enable Mail Notification mail_notify = Enable Mail Notification
@ -512,6 +514,8 @@ dashboard.delete_repo_archives = Delete all repositories archives
dashboard.delete_repo_archives_success = All repositories archives have been deleted successfully. dashboard.delete_repo_archives_success = All repositories archives have been deleted successfully.
dashboard.git_gc_repos = Do garbage collection on repositories dashboard.git_gc_repos = Do garbage collection on repositories
dashboard.git_gc_repos_success = All repositories have done garbage collection successfully. dashboard.git_gc_repos_success = All repositories have done garbage collection successfully.
dashboard.resync_all_sshkeys = Rewrite '.ssh/autorized_key' file(caution: non-Gogs keys will be lost)
dashboard.resync_all_sshkeys_success = All public keys have been rewritten successfully.
dashboard.server_uptime = Server Uptime dashboard.server_uptime = Server Uptime
dashboard.current_goroutine = Current Goroutines dashboard.current_goroutine = Current Goroutines
dashboard.current_memory_usage = Current Memory Usage dashboard.current_memory_usage = Current Memory Usage
@ -712,16 +716,3 @@ months = %d months %s
years = %d years %s years = %d years %s
raw_seconds = seconds raw_seconds = seconds
raw_minutes = minutes raw_minutes = minutes

728
conf/locale/locale_ja-JP.ini Executable file
View File

@ -0,0 +1,728 @@
app_desc=Go言語で実装したセルフホストGitサーバ
home=ホーム
dashboard=ダッシュボード
explore=エスクプローラ
help=ヘルプ
sign_in=サインイン
social_sign_in=SNSでサインイン: ステップ2 <small>アカウント連携</small>
sign_out=サインアウト
sign_up=サインアップ
register=登録
website=WEBサイト
version=バージョン
page=ページ
template=テンプレート
language=言語
username=ユーザ名
email=E-mail
password=パスワード
re_type=再入力
captcha=キャプチャ
repository=リポジトリ
organization=組織
mirror=ミラー
new_repo=新しいリポジトリ
new_migrate=新しい移行
new_fork=新しいフォークのリポジトリ
new_org=新しい組織
manage_org=組織を管理
admin_panel=管理者パネル
account_settings=アカウント設定
settings=設定
news_feed=ニュースのフィード
pull_requests=プルリクエスト
issues=課題
cancel=キャンセル
[install]
install=インストール
title=初回実行のインストール手順
requite_db_desc=Gogs には、MySQL や PostgreSQL 、SQLite3 が必要です。
db_type=データベースの種類
host=ホスト
user=ユーザ
password=パスワード
db_name=データベース名
db_helper=Mysql INNODB エンジン utf8_general_ci の文字セットを使用してください。
ssl_mode=SSL モード
path=パス
sqlite_helper=SQLite3 データベースのファイル パス
general_title=Gogs の全般設定
repo_path=リポジトリのルートパス
repo_path_helper=すべての Git リモート リポジトリはこのディレクトリに保存されます。
run_user=実行ユーザ
run_user_helper=ユーザーはリポジトリ ルートパスへのアクセス、及びGogs を実行する権限を所有する必要があります。
domain=ドメイン
domain_helper=これはSSHクローンURLに影響する。
app_url=アプリケーションの URL
app_url_helper=この設定は、HTTP / HTTPSのクローンURLおよび、一部のメールボックスへのリンクに影響を与えます。
email_title=E-mailサービス設定(Optional)
smtp_host=SMTP ホスト
mailer_user=送信者の電子メール
mailer_password=送信者のパスワード
notify_title=通知 Settings(Optional)
register_confirm=登録の確認を有効にする
mail_notify=メール通知を有効にする
admin_title=管理者アカウントの設定
admin_name=ユーザ名
admin_password=パスワード
confirm_password=パスワード確認
admin_email=E-mail
install_gogs=Gogs をインストール
test_git_failed='Git' コマンドテストに失敗: %v
sqlite3_not_available=このリリース バージョンは SQLite3 をサポートしていません。gobuild バージョンではない、公式のバイナリ バージョンを %s からダウンロードしてください。
invalid_db_setting=データベースの設定が正しくありません: %v
invalid_repo_path=リポジトリのルート パスが無効です: %v
run_user_not_match=実行ユーザーは、現在のユーザーではない: %s-> %s
save_config_failed=構成の保存に失敗した: %v
invalid_admin_setting=管理者アカウントの設定が無効です: %v
install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう!
[home]
uname_holder=ユーザー名またはEメール
password_holder=パスワード
switch_dashboard_context=ダッシュ ボードのコンテキストを切替
my_repos=私のリポジトリ
collaborative_repos=共同リポジトリ
my_orgs=私の組織
my_mirrors=私のミラー
[explore]
repos=リポジトリ
[auth]
create_new_account=新規アカウントを作成
register_hepler_msg=すでにアカウントをお持ちですか?今すぐログイン
social_register_hepler_msg=すでにアカウントをお持ちですか?今すぐバインド
disable_register_prompt=申し訳ありませんが、登録が無効になっています。サイト管理者に問い合わせてください。
disable_register_mail=申し訳ありませんが、登録メールの確認機能が無効になっています。
remember_me=ログイン状態を保持する
forgot_password=パスワードを忘れた
forget_password=パスワードを忘れた?
sign_up_now=アカウントが必要ですか?今すぐサインアップ
confirmation_mail_sent_prompt=新しい確認メールを <b>%s</b> に送りました。登録を完了させるために、%d時間以内にあなたのメールボックスを確認してください。
sign_in_email=E-mailでサイイン
active_your_account=アカウントをアクティブ
resent_limit_prompt=申し訳ありませんが、アクティベーションメールは頻繁に送信しています。3 分お待ちください。
has_unconfirmed_mail=こんにちは %s さん、あなたの電子メール アドレス (<b>%s</b>) は未確認です。もし確認メールをまだ確認できていないか、改めて再送信する場合は、下のボタンをクリックしてください。
resend_mail=アクティベーションメールを再送信するにはここをクリック
email_not_associate=この電子メール アドレスは、アカウントには関連付けられません。
send_reset_mail=パスワードリセットのメールを再送するにはここをクリック
reset_password=パスワードリセット
invalid_code=申し訳ありませんが、確認用コードが期限切れまたは無効です。
reset_password_helper=パスワードをリセットするにはここをクリック
password_too_short=6文字未満のパスワードは設定できません。
[form]
UserName=ユーザ名
RepoName=リポジトリ名
Email=Eメールアドレス
Password=パスワード
Retype=パスワードを再入力
SSHTitle=SSH キーの名前
HttpsUrl=HTTPS URL
PayloadUrl=ペイロードの URL
TeamName=チーム名
AuthName=承認名
AdminEmail=管理者の電子メール
require_error=空にできません
alpha_dash_error=アルファベット、数字、ハイフン"-"、アンダースコア"_"のいずれかの必要があります
alpha_dash_dot_error=' アルファベット、数値、ダッシュ(-)、アンダースコア(_) 、ドット(.)のいずれかを入力する必要があります。 '
min_size_error=' 少なくとも %s 文字の必要があります '
max_size_error=' %s 文字以下の必要があります '
email_error=' は有効な電子メール アドレスではない '
url_error=' は有効な URL はありません。 '
unknown_error=不明なエラー:
captcha_incorrect=Captcha が一致しませんでした。
password_not_match=パスワードと確認用パスワードが一致同していません。
username_been_taken=ユーザー名は既に使用されています。
repo_name_been_taken=リポジトリ名は既に使用されています。
org_name_been_taken=組織名は既に使用されています。
team_name_been_taken=チーム名は既に使用されています。
email_been_used=電子メール アドレスは既に使用されています。
ssh_key_been_used=パブリック キー名が使用されています。
illegal_username=あなたのユーザ名に無効な文字が含まれます。
illegal_repo_name=リポジトリ名には無効な文字が含まれています。
illegal_org_name=組織名に無効な文字が含まれています。
illegal_team_name=チーム名に無効な文字が含まれています。
username_password_incorrect=ユーザー名またはパスワードが正しくありません。
enterred_invalid_repo_name=入力したリポジトリの名前が正しいかどうかを確認してください。
enterred_invalid_owner_name=入力された所有者名が正しいかどうかを確認してください。
enterred_invalid_password=入力したパスワードが正しいかを確認してください。
user_not_exist=指定されたユーザーは存在しません。
last_org_owner=削除するユーザーはチームの最後のメンバーです。別の所有者設定が必要です。
invalid_ssh_key=SSHを確認できません:%s
unable_verify_ssh_key=GogsはあなたのSSH keyを確認できません。しかし、我々は有効とみなしますので、自分自身で確認してください。
auth_failed=認証に失敗しました: %v
still_own_repo=アカウント所有のリポジトリがあり、リポジトリの削除または所有者の移譲が必要です。
still_has_org=アカウントはまだ組織のメンバーであり、組織から退出するか削除する必要があります。
org_still_own_repo=この組織はまだリポジトリの所有しています、リポジトリを削除または転送する必要があります。
still_own_user=この認証はまだ一部のユーザーによって使用されています。一部のユーザを移動させてから、もう一度削除してください。
target_branch_not_exist=ターゲットブランチが存在しない
[user]
change_avatar=gravatar.com で自分のアバターを変更
change_custom_avatar=設定で自分のアバターを変更
join_on=参加しました
repositories=リポジトリ
activity=パブリック・アクティビティ
followers=フォロワー
starred=スター
following=フォロー
[settings]
profile=プロフィール
password=パスワード
ssh_keys=SSH キー
social=SNSアカウント
applications=アプリケーション
orgs=組織
delete=アカウントを削除
uid=Uid
public_profile=パブリック プロフィール
profile_desc=あなたのメールアドレスは公開され、任意のアカウント関連の通知に使用されます。また、Webベースの操作はサイトを介して行います。
full_name=フルネーム
website=WEBサイト
location=ロケーション
update_profile=プロファイル更新
update_profile_success=あなたのプロフィールが更新されました。
change_username=ユーザー名が変更されました
change_username_desc=ユーザー名が変更されている、継続したいですか?これはあなたのアカウントに関連するすべてのリンクに影響を与える。
continue=続行
cancel=キャンセル
enable_custom_avatar=カスタムのアバターを有効にする
enable_custom_avatar_helper=Gravatarからのフェッチを無効にするのを、有効にします
choose_new_avatar=新しいアバターを選択
update_avatar=アバターの設定を更新
uploaded_avatar_not_a_image=アップロードされたファイルは画像ではない。
no_custom_avatar_available=利用可能なカスタム アバターがないため、有効にできません。
update_avatar_success=あなたのアバターの設定が更新されました。
change_password=パスワードを変更
old_password=現在のパスワード
new_password=新しいパスワード
password_incorrect=現在のパスワードが正しくありません。
change_password_success=パスワードが正常に変更されました。今すぐ新しいパスワード経由でサインインすることができます。
emails=E-mail アドレス
manage_emails=E-mail アドレスを管理
email_desc=あなたのプライマリメールアドレスは、通知やその他の操作に使用されます。
primary=プライマリー
primary_email=プライマリに設定
delete_email=削除
add_new_email=新しいe-mailアドレスを追加
add_email=電子メールを追加します。
add_email_success=新しいe-mail アドレスが追加されました。
manage_ssh_keys=SSH キーを管理
add_key=キーを追加
ssh_desc=これはあなたのアカウントに関連付けられている SSH キーの一覧です。あなたが認識していないキーを削除します。
ssh_helper=<strong>ヘルプが必要ですか?</strong> 我々のガイドをご覧ください。 <a href="%s"> SSH キーを生成</a> <a href="%s"> SSH の一般的な問題</a>
add_new_key=SSH キーを追加
key_name=キーの名前
key_content=コンテンツ
add_key_success=新しい SSH キーが追加されました
delete_key=削除
add_on=追加された
last_used=最終使用日
no_activity=最近の活動なし
manage_social=関連付けられているSNSアカウントを管理
social_desc=これは関連付けられたソーシャルアカウントのリストです。あなたが認識していない結び付けを削除します。
unbind=バインド解除
unbind_success=SNSアカウントがバインドされていない。
manage_access_token=個人のアクセス トークンを管理
generate_new_token=新しいトークンを生成
tokens_desc=生成したトークンを利用して Gogs の API にアクセスすることができます。
new_token_desc=今のところ、全てのトークンはあなたのアカウントにフルアクセスできます。
token_name=トークン名
generate_token=トークンを生成
generate_token_succees=新しいアクセス トークンは正常に生成されました !今すぐあなたの新しいアクセス トークンをコピーしておいてください。二度と見ることはできませんので確認してください!
delete_token=削除
delete_token_success=個人のアクセス トークンは正常に削除されました!同時にあなたのアプリケーションを更新することを忘れないでください。
delete_account=アカウントを削除
delete_prompt=この操作はあなたのアカウントを完全に削除し、復旧<strong>できない</strong>
confirm_delete_account=削除の確認
delete_account_title=アカウントの削除
delete_account_desc=このアカウントは永久に削除しようとしている、継続しますか?
[repo]
owner=オーナー
repo_name=リポジトリ名
repo_name_helper=偉大なリポジトリ名は短い。思い出に残り、そして<strong>一意</strong>だ。
visibility=ビジビリティ
visiblity_helper=このリポジトリは <span class="label label-red label-radius"> プライベート</span> です。
fork_repo=フォークのリポジトリ
fork_from=フォーク元
fork_visiblity_helper=フォークされたリポジトリは可視状態を変更できません
repo_desc=説明
repo_lang=言語
repo_lang_helper=.gitignore ファイルを選択
license=ライセンス
license_helper=ライセンス ファイルを選択
init_readme=README.md 付きでリポジトリを初期化
create_repo=リポジトリを作成
default_branch=デフォルトのブランチ
mirror_interval=ミラー 間隔(時)
goget_meta=Go-Get メタ
goget_meta_helper=このリポジトリは <span class="label label-blue label-radius"> Go-Getable </span> になります
need_auth=認証が必要
migrate_type=マイグレーションの種類
migrate_type_helper=このリポジトリは <span class="label label-blue label-radius"> ミラー</span> になります
migrate_repo=リポジトリを移行
copy_link=コピー
click_to_copy=クリップボードにコピー
copied=コピー成功
clone_helper=クローニングのヘルプが必要ですか?<a target="_blank"href="%s"> ヘルプ</a> を参照してください!
unwatch=Unwatch
watch=Watch
unstar=Unstar
star=Star
fork=Fork
no_desc=説明なし
quick_guide=クイック ガイド
clone_this_repo=このリポジトリのクローンを作成
create_new_repo_command=コマンドラインで新しいリポジトリを作成します。
push_exist_repo=コマンド ・ ラインから既存のリポジトリをプッシュ
branch=ブランチ
tree=ツリー
branch_and_tags=ブランチ& タグ
branches=ブランチ
tags=タグ
issues=課題
commits=コミット
releases=リリース
file_raw=生データ
file_history=履歴
file_view_raw=生データを見る
commits.commits=コミット
commits.search=コミットの検索
commits.find=検索
commits.author=作者
commits.message=メッセージ
commits.date=日付
commits.older=古い
commits.newer=新しい
settings=設定
settings.options=オプション
settings.collaboration=コラボレーション
settings.hooks=Webhooks
settings.githooks=Git のフック
settings.deploy_keys=デプロイキー
settings.basic_settings=基本設定
settings.danger_zone=危険地帯
settings.site=公式サイト
settings.update_settings=設定の更新
settings.change_reponame=リポジトリ名が変更されました
settings.change_reponame_desc=リポジトリの名前が変更されています、継続しますか?このリポジトリ関連すべてのリンクに影響を与えます。
settings.transfer=オーナー移転
settings.transfer_desc=リポジトリをあなたが管理者権限を持っている別のユーザーまた組織に移譲します。
settings.new_owner_has_same_repo=新しいオーナーは、既に同じ名前のリポジトリを持っています。
settings.delete=このリポジトリを削除
settings.delete_desc=リポジトリを削除すると元に戻せません。確実に確認してください。
settings.transfer_notices=<p>-新オーナーは個人ユーザの場合、あなたはにアクセスできなくなります。</p><p>-新オーナーは組織であり、かつあなたが組織のオーナーに所属する場合、あなたはアクセス権を維持します。</p>
settings.update_settings_success=リポジトリ オプションが更新されました。
settings.transfer_owner=新しいオーナー
settings.make_transfer=転送
settings.transfer_succeed=リポジトリの所有権は正常に転送されました。
settings.confirm_delete=削除の確認
settings.add_collaborator=新しい共同編集者を追加
settings.add_collaborator_success=新しい共同編集者が追加されました。
settings.remove_collaborator_success=共同編集者が削除されました。
settings.user_is_org_member=ユーザーは組織の一員なので、共同編集者として追加することはできません。
settings.add_webhook=Webhook を追加
settings.hooks_desc=Webhooksは、Gogsで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
settings.githooks_desc=Git のフックは Git 自体によって提供されています。以下のリストのファイルを編集して、サポートされているフックのカスタム操作を適用することができます。
settings.githook_edit_desc=もしフックがアクティブではない場合は、サンプルコンテンツが表示されます。コンテンツを空白にするにはこのフックを無効にします。
settings.githook_name=フックの名前
settings.githook_content=コンテンツをフック
settings.update_githook=フックを更新
settings.remove_hook_success=Webhookが削除されました。
settings.add_webhook_desc=私たちは、指定されたURLに購読されたイベントの詳細を <code>POST</code>リクエストとして送信します。あなたは、異なるデータ受信モード(JSONまたは, <code>x-www-form-urlencoded</code>, <em>その他</em>) を設定することができます。詳細については、<a target="_blank" href="%s">Webhookガイド</a>を参照してください。
settings.payload_url=ペイロードの URL
settings.content_type=コンテンツ タイプ
settings.secret=秘密
settings.event_desc=どのイベントをこのWEBフックのトリガーにしますか
settings.event_push_only=<code>push</code> イベントのみ
settings.active=アクティブ
settings.active_helper=このフックのトリガーが引かれた時に、イベントの詳細を配信します。
settings.add_hook_success=新しい webhook が追加されました。
settings.update_webhook=Webhookを更新
settings.update_hook_success=Webhook を更新しました。
settings.delete_webhook=Webhook を削除
settings.recent_deliveries=最近のデリバリー
settings.hook_type=フックタイプ
settings.add_slack_hook_desc=<a href="%s"> Slack</a> インテグレーションをリポジトリに追加します。
settings.slack_token=トークン
settings.slack_domain=ドメイン
settings.slack_channel=チャンネル
diff.browse_source=ソースを参照
diff.parent=
diff.commit=コミット
diff.data_not_available=差分データは利用できません。
diff.show_diff_stats=差分情報を表示
diff.stats_desc=共有<strong>%d 個のファイルを変更した</strong>、<strong>%d 個の追加</strong> と <strong>%d 個の削除</strong>を含む
diff.bin=BIN
diff.view_file=ファイルの表示
release.releases=リリース
release.new_release=新しいリリース
release.draft=ドラフト
release.prerelease=プレリリース
release.stable=安定
release.edit=編集
release.ahead=このリリース以降 %s へ <strong>%d</strong> コミット
release.source_code=ソース コード
release.tag_name=タグ名
release.target=ターゲット
release.tag_helper=既存のタグを選択するか、新しいタグを作成し発行します。
release.release_title=リリース タイトル
release.content_with_md=<a href="%s"> Markdown</a> コンテンツ
release.write=書込み
release.preview=プレビュー
release.content_placeholder=コンテンツを書く
release.loading=読み込み中…
release.prerelease_desc=これはリリース前のものです
release.prerelease_helper=このリリースは非プロダクション利用として識別します。
release.publish=リリースを発行
release.save_draft=下書きを保存
release.edit_release=リリースを編集
release.tag_name_already_exist=このタグ名には既にリリースが存在します。
[org]
org_name_holder=組織名
org_name_helper=偉大な組織の名は短く覚えやすいです。
org_email_helper=組織の電子メールはすべての通知や確認を受け取ります。
create_org=組織を作成
repo_updated=更新した
people=人々
invite_someone=誰かを招待
teams=チーム
lower_members=メンバー
lower_repositories=リポジトリ
create_new_team=新しいチームを作成
org_desc=説明
team_name=チーム名
team_desc=説明
team_name_helper=会話の時、この名前を使用しチーム名を表明します。
team_desc_helper=このチームに関する全ての情報は?
team_permission_desc=このチームに必要な権限レベルは?
settings=設定
settings.options=オプション
settings.full_name=フルネーム
settings.website=WEBサイト
settings.location=ロケーション
settings.update_settings=設定の更新
settings.change_orgname=組織名が変更されました
settings.change_orgname_desc=組織名が変更されています、継続しますか?これはすべての関連リンクに影響を与えます。
settings.update_setting_success=組織の設定が更新されました。
settings.delete=組織を削除
settings.delete_account=この組織を削除
settings.delete_prompt=操作はこの組織を完全に削除し、復旧<strong>できない</strong>
settings.confirm_delete_account=削除の確認
settings.delete_org_title=組織の削除
settings.delete_org_desc=この組織は完全に削除されます、継続しますか?
settings.hooks_desc=この組織のもとで <strong>すべてのリポジトリ</strong> に対してトリガーされる webhook を追加します。
members.public=パブリック
members.public_helper=プライベートにする
members.private=プライベート
members.private_helper=公開する
members.owner=オーナー
members.member=メンバー
members.conceal=隠す
members.remove=削除
members.leave=退出
members.invite_desc=%s に招待する新しいメンバーをユーザ名を入力してください:
members.invite_now=今すぐ招待
teams.join=参加
teams.leave=退出
teams.read_access=読み取りアクセス権
teams.read_access_helper=このチームはリポジトリの閲覧とクローンをすることができます。
teams.write_access=書き込みアクセス権
teams.write_access_helper=このチームはリポジトリを読むだけではなく、プッシュすることもできます。
teams.admin_access=管理者のアクセス権
teams.admin_access_helper=このチームはリポジトリにプッシュ/プル、及び他の共同編集者を追加することができます。
teams.no_desc=このチームは説明がありません。
teams.settings=設定
teams.owners_permission_desc=オーナーは<strong>すべてのリポジトリ</strong> へのフルアクセス権、組織の <strong>管理権限</strong>を持ちます。
teams.members=チーム メンバー
teams.update_settings=設定の更新
teams.delete_team=このチームを削除
teams.add_team_member=チーム メンバーを追加
teams.delete_team_title=チームの削除
teams.delete_team_desc=このチームを削除します、継続しますか?このチームのメンバーはいくつかのリポジトリへのアクセスを失う可能性があります。
teams.delete_team_success=指定のチームが正常に削除されました。
teams.read_permission_desc=このチームは<strong>読み取り</strong>権限を持ち: メンバーはリポジトリの表示及びクローンの作成ができます。
teams.write_permission_desc=このチームは<strong>書き込み</strong>権限を持ち: メンバーはリポジトリの表示及リポジトリへのプッシュができます。
teams.admin_permission_desc=このチームは<strong>管理者</strong>の権限を持ち: メンバーはチームのリポジトリに対して、読み取り、プッシュや共同編集者の追加ができます。
teams.repositories=チームのリポジトリ
teams.add_team_repository=チームのリポジトリを追加
teams.remove_repo=削除(Remove)
teams.add_nonexistent_repo=追加しようとしているリポジトリは存在しません。まずはじめに作成してください。
[admin]
dashboard=ダッシュボード
users=ユーザ
organizations=組織
repositories=リポジトリ
authentication=認証
config=コンフィギュレーション
notices=システム通知
monitor=モニタリング
prev=前へ
next=次へ
dashboard.statistic=統計
dashboard.operations=操作
dashboard.system_status=システム モニターのステータス
dashboard.statistic_info=Gogs データベースは <b>%d</b> ユーザ, <b>%d</b> 組織, <b>%d</b> 公開鍵, <b>%d</b> リポジトリ, <b>%d</b> ウォッチ, <b>%d</b> スター, <b>%d</b> 行動, <b>%d</b> アクセス, <b>%d</b> 問題, <b>%d</b> コメント, <b>%d</b> ソーシャルアカウント, <b>%d</b> フォロー, <b>%d</b> ミラー, <b>%d</b> リリース, <b>%d</b> ログイン元, <b>%d</b> webhook, <b>%d</b> マイルストーン, <b>%d</b> ラベル, <b>%d</b> フックタスク, <b>%d</b> チーム, <b>%d</b> アップデートタスク, <b>%d</b> 添付ファイル の情報を持っています。
dashboard.operation_name=操作の名前
dashboard.operation_switch=スイッチ
dashboard.operation_run=実行
dashboard.clean_unbind_oauth=結び付けられていない OAuth をクリーン
dashboard.clean_unbind_oauth_success=結び付けられていない全ての OAuth を正常に削除しました。
dashboard.delete_inactivate_accounts=非アクティブのアカウントをすべて削除
dashboard.delete_inactivate_accounts_success=すべての非アクティブアカウントは正常に削除されました。
dashboard.delete_repo_archives=リポジトリのすべてのアーカイブを削除
dashboard.delete_repo_archives_success=リポジトリのすべてのアーカイブが正常に削除されました。
dashboard.git_gc_repos=リポジトリでのガベージコレクションを実行します。
dashboard.git_gc_repos_success=すべてのリポジトリは正常にガベージ コレクションを行いました。
dashboard.server_uptime=サーバーの稼働時間
dashboard.current_goroutine=現在のGoroutine
dashboard.current_memory_usage=現在のメモリ使用量
dashboard.total_memory_allocated=割り当てられたメモリの合計
dashboard.memory_obtained=配分されたメモリ量
dashboard.pointer_lookup_times=ポインタ参照回数
dashboard.memory_allocate_times=メモリ割当回数
dashboard.memory_free_times=メモリ解放回数
dashboard.current_heap_usage=現在のヒープ使用量
dashboard.heap_memory_obtained=配分されたヒープ メモリ量
dashboard.heap_memory_idle=アイドルのヒープ メモリ量
dashboard.heap_memory_in_use=使用中のヒープ メモリ
dashboard.heap_memory_released=ヒープ メモリが解放されました
dashboard.heap_objects=ヒープ オブジェクト
dashboard.bootstrap_stack_usage=ブートストラップスタック使用量
dashboard.stack_memory_obtained=配分されたスタック メモリ量
dashboard.mspan_structures_usage=MSpan 構造体の使用量
dashboard.mspan_structures_obtained=配分されたMSpan 構造体
dashboard.mcache_structures_usage=MCache 構造体の使用量
dashboard.mcache_structures_obtained=分配されたMCache 構造体
dashboard.profiling_bucket_hash_table_obtained=ハッシュテーブル分析に割り当てられたメモリ
dashboard.gc_metadata_obtained=GCメタデータ取得
dashboard.other_system_allocation_obtained=他のシステムに割り当てられたメモリ
dashboard.next_gc_recycle=次回のGCリサイクル
dashboard.last_gc_time=前回GCからの時間
dashboard.total_gc_time=GC一時停止の合計
dashboard.total_gc_pause=GC一時停止の合計
dashboard.last_gc_pause=直近のGC一時停止
dashboard.gc_times=GC実行回数
users.user_manage_panel=ユーザー管理パネル
users.new_account=新規アカウントを作成
users.name=名前
users.activated=アクティブ化
users.admin=アドミン
users.repos=リポジトリ
users.created=作成されました
users.edit=編集
users.auth_source=認証元
users.local=ローカル
users.auth_login_name=認証ログイン名
users.update_profile_success=アカウントのプロファイルが更新されました。
users.edit_account=アカウントの編集
users.is_activated=アカウントがアクティブされました
users.is_admin=このアカウントには管理者の権限を持つ
users.allow_git_hook=このアカウントには Git のフックを作成する権限を持つ
users.update_profile=アカウント ・ プロファイルを更新
users.delete_account=このアカウントを削除
users.still_own_repo=アカウント所有のリポジトリがあり、リポジトリの削除または所有者の移譲が必要です。
users.still_has_org=アカウントはまだ組織のメンバーであり、組織から退出するか削除する必要があります。
orgs.org_manage_panel=組織の管理パネル
orgs.name=名前
orgs.teams=チーム
orgs.members=メンバー
repos.repo_manage_panel=リポジトリの管理パネル
repos.owner=オーナー
repos.name=名前
repos.private=プライベート
repos.watches=Watches
repos.stars=Stars
repos.issues=課題
auths.auth_manage_panel=承認の管理パネル
auths.new=新しい認証元を追加
auths.name=名前
auths.type=タイプ
auths.enabled=Enabled
auths.updated=Updated
auths.auth_type=認証の種類
auths.auth_name=認証名
auths.domain=ドメイン
auths.host=ホスト
auths.port=ポート
auths.base_dn=ベースのドメイン名
auths.attributes=属性検索
auths.filter=検索フィルター
auths.ms_ad_sa=Ms Ad SA
auths.smtp_auth=SMTP 認証の種類
auths.smtphost=SMTP ホスト
auths.smtpport=SMTP ポート
auths.enable_tls=TLS 暗号化を有効にする
auths.enable_auto_register=自動登録を有効にする
auths.tips=ヒント
auths.edit=認証設定を編集
auths.activated=認証がアクティブされました
auths.update_success=認証の設定が正常に更新されました。
auths.update=認証設定の更新
auths.delete=この権限を削除
auths.delete_auth_title=認証の削除
auths.delete_auth_desc=認証を削除します、継続しますか?
config.server_config=サーバーの構成
config.app_name=アプリケーション名
config.app_ver=アプリケーションのバージョン
config.app_url=アプリケーションの URL
config.domain=ドメイン
config.offline_mode=オフラインモード
config.disable_router_log=ルーターのログを無効にする
config.run_user=実行ユーザ
config.run_mode=実行モード
config.repo_root_path=リポジトリのルートパス
config.static_file_root_path=静的ファイルのルートパス
config.log_file_root_path=ログ ファイルのルート パス
config.script_type=スクリプトの種類
config.reverse_auth_user=リバース認証ユーザ
config.db_config=データベースの構成
config.db_type=タイプ
config.db_host=ホスト
config.db_name=名前
config.db_user=ユーザ
config.db_ssl_mode=SSL モード
config.db_ssl_mode_helper=(「postgres」のみ
config.db_path=パス
config.db_path_helper=(「sqlite3」のみ
config.service_config=サービスの構成
config.register_email_confirm=電子メールの確認を必要
config.disable_register=登録を無効にする
config.require_sign_in_view=サインインを要求
config.mail_notify=メール通知
config.enable_cache_avatar=アバターのキャッシュを有効にします。
config.active_code_lives=コードリンクの有効期限をアクティブ
config.reset_password_code_lives=パスワードリンクの有効期限をリセット
config.webhook_config=Webhook設定
config.task_interval=タスクの間隔
config.deliver_timeout=送信タイムアウト
config.mailer_config=メーラーの構成
config.mailer_enabled=有効にした
config.mailer_name=名前
config.mailer_host=ホスト
config.mailer_user=ユーザ
config.oauth_config=OAuth 構成
config.oauth_enabled=Enabled
config.cache_config=キャッシュの構成
config.cache_adapter=キャッシュ アダプター
config.cache_interval=キャッシュ間隔
config.cache_conn=キャッシュ接続
config.session_config=セッションの構成
config.session_provider=セッション プロバイダー
config.provider_config=プロバイダーの構成
config.cookie_name=クッキー名
config.enable_set_cookie=クッキーの設定を有効にする
config.gc_interval_time=GC 間隔
config.session_life_time=セッションのライフタイム
config.https_only=HTTPS のみ
config.cookie_life_time=クッキーのライフタイム
config.picture_config=画像構成
config.picture_service=画像サービス
config.disable_gravatar=グラバターを無効にする
config.log_config=ログの構成
config.log_mode=ログ モード
monitor.cron=Cron タスク
monitor.name=名前
monitor.schedule=スケジュール
monitor.next=次回
monitor.previous=前回
monitor.execute_times=実行回数
monitor.process=実行中のプロセス
monitor.desc=説明
monitor.start=開始日時
monitor.execute_time=実行時間:
notices.system_notice_list=システム通知
notices.type=タイプ
notices.type_1=リポジトリ
notices.desc=説明
notices.op=Op。
notices.delete_success=システム通知が正常に削除されました。
[action]
create_repo=リポジトリ <a href="%s/%s"> %s</a>を作成しました
commit_repo=<a href="%s/%s">%s</a>を<a href="%s/%s/src/%s">%s</a>にプッシュしました
create_issue=問題 <a href="%s/%s/issues/%s"> %s #%s</a> を開きました
comment_issue=問題 <a href="%s/%s/issues/%s"> %s #%s</a> のコメント
transfer_repo=リポジトリ <code>%s</code> を <a href="/%s%s">%s</a> へ転送しました
push_tag=<a href="%s/%s">%s</a> に タグ <a href="%s/%s/src/%s">%s</a> をプッシュしました
compare_2_commits=これら 2 のコミットの比較を閲覧する
[tool]
ago=
from_now=今から
now=
1s=1 秒 %s
1m=1 分 %s
1h=1 時間 %s
1d=1 日 %s
1w=1 週間 %s
1mon=1 ヶ月 %s
1y=1 年間 %s
seconds=%d 秒 %s
minutes=%d 分の %s
hours=%d 時間 %s
days=%d 日 %s
weeks=%d 週間 %s
months=%d ヶ月 %s
years=%d 年 %s
raw_seconds=
raw_minutes=

View File

@ -61,7 +61,7 @@ domain=Домен
domain_helper=This affects SSH clone URLs. domain_helper=This affects SSH clone URLs.
app_url=URL приложения app_url=URL приложения
app_url_helper=This affects HTTP/HTTPS clone URL and somewhere in e-mail. app_url_helper=This affects HTTP/HTTPS clone URL and somewhere in e-mail.
email_title=E-mail Service Settings (Optional) email_title=Настройки службы электронной почты (опционально)
smtp_host=Узел SMTP smtp_host=Узел SMTP
mailer_user=Электронная почта отправителя mailer_user=Электронная почта отправителя
mailer_password=Пароль отправителя mailer_password=Пароль отправителя
@ -75,7 +75,7 @@ confirm_password=Подтвердить пароль
admin_email=Эл. почта admin_email=Эл. почта
install_gogs=Установить Gogs install_gogs=Установить Gogs
test_git_failed=Не удалось проверить 'git' команду: %v test_git_failed=Не удалось проверить 'git' команду: %v
sqlite3_not_available=Your release version does not support SQLite3, please download the official binary version from %s, NOT the gobuild version. sqlite3_not_available=Ваша версия не поддерживает SQLite3, пожалуйста скачайте официальную бинарную версию от %s, а не версию gobuild.
invalid_db_setting=Настройки базы данных не правильные: %v invalid_db_setting=Настройки базы данных не правильные: %v
invalid_repo_path=Недопустимый путь к корню репозитория: %v invalid_repo_path=Недопустимый путь к корню репозитория: %v
run_user_not_match=Run user isn't the current user: %s -> %s run_user_not_match=Run user isn't the current user: %s -> %s
@ -98,9 +98,9 @@ repos=Репозитории
[auth] [auth]
create_new_account=Создать новый аккаунт create_new_account=Создать новый аккаунт
register_hepler_msg=Уже есть аккаунт? Авторизуйтесь! register_hepler_msg=Уже есть аккаунт? Авторизуйтесь!
social_register_hepler_msg=Уже есть учетная запись? Свяжите ее соцсетью! social_register_hepler_msg=Уже есть учетная запись? Свяжите ее с соцсетью!
disable_register_prompt=Извините, возможность регистрации отключена. Пожалуйста, свяжитесь с администратором сайта. disable_register_prompt=Извините, возможность регистрации отключена. Пожалуйста, свяжитесь с администратором сайта.
disable_register_mail=Sorry, Register Mail Confirmation has been disabled. disable_register_mail=К сожалению подтверждение регистрации по почте отключено.
remember_me=Запомнить меня remember_me=Запомнить меня
forgot_password=Забыли пароль forgot_password=Забыли пароль
forget_password=Забыли пароль? forget_password=Забыли пароль?
@ -109,7 +109,7 @@ confirmation_mail_sent_prompt=Новое письмо для подтвержд
sign_in_email=Войдите в свой адрес электронной почты sign_in_email=Войдите в свой адрес электронной почты
active_your_account=Активируйте свой аккаунт active_your_account=Активируйте свой аккаунт
resent_limit_prompt=Вы слишком часто отправляете письмо с активацией. Подождите 3 минуты, пожалуйста. resent_limit_prompt=Вы слишком часто отправляете письмо с активацией. Подождите 3 минуты, пожалуйста.
has_unconfirmed_mail=Hi %s, you have an unconfirmed e-mail address <b>%s</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click on the button below. has_unconfirmed_mail=Здравствуйте, %s! У вас есть неподтвержденный адрес электронной почты (<b>%s</b>). Если вам не приходило письмо с подтверждением или нужно выслать новое письмо, нажмите на кнопку ниже.
resend_mail=Нажмите здесь, чтобы переотправить активационное письмо resend_mail=Нажмите здесь, чтобы переотправить активационное письмо
email_not_associate=Этот адрес электронной почты не связан ни с одной учетной записью. email_not_associate=Этот адрес электронной почты не связан ни с одной учетной записью.
send_reset_mail=Нажмите сюда, чтобы отправить письмо для сброса пароля send_reset_mail=Нажмите сюда, чтобы отправить письмо для сброса пароля
@ -157,17 +157,17 @@ enterred_invalid_repo_name=Пожалуйста, убедитесь, что вв
enterred_invalid_owner_name=Убедитесь, что введенное имя владельца верное. enterred_invalid_owner_name=Убедитесь, что введенное имя владельца верное.
enterred_invalid_password=Убедитесь, что введенный пароль верен. enterred_invalid_password=Убедитесь, что введенный пароль верен.
user_not_exist=Данный пользователь не существует. user_not_exist=Данный пользователь не существует.
last_org_owner=The user to remove is the last member in owner team. There must be another owner. last_org_owner=Удаляемый пользователь является последним в команде владельцев. Должен быть хотя бы один владелец.
invalid_ssh_key=К сожалению, мы не смогли проверить ваш SSH-ключ: %s invalid_ssh_key=К сожалению, мы не смогли проверить ваш SSH-ключ: %s
unable_verify_ssh_key=Gogs не может проверить ваш SSH-ключ, но мы допускаем, что он действителен. Пожалуйста, удостоверьтесь самостоятельно, что ключ действителен. unable_verify_ssh_key=Gogs не может проверить ваш SSH-ключ, но мы допускаем, что он действителен. Пожалуйста, удостоверьтесь самостоятельно, что ключ действителен.
auth_failed=Ошибка аутентификации: %v auth_failed=Ошибка аутентификации: %v
still_own_repo=Your account still have ownership of repository, you have to delete or transfer them first. still_own_repo=На вашем аккаунте все еще остается как минимум один репозиторий, сначала вам нужно удалить или передать его.
still_has_org=Your account still have membership of organization, you have to left or delete them first. still_has_org=Вы находитесь в организации, сперва Вам необходимо покинуть ее или удалить.
org_still_own_repo=Данная организация все еще является владельцем репозиториев, необходимо удалить или переместить их в начале. org_still_own_repo=Данная организация все еще является владельцем репозиториев, необходимо удалить или переместить их в начале.
still_own_user=This authentication still has used by some users, you should move them and then delete again. still_own_user=Эта проверка подлинности по-прежнему используется некоторыми пользователями, вы должны переместить их и затем снова удалить.
target_branch_not_exist=Целевая ветка не существует target_branch_not_exist=Целевая ветка не существует
@ -192,7 +192,7 @@ delete=Удалить аккаунт
uid=UID uid=UID
public_profile=Открытый профиль public_profile=Открытый профиль
profile_desc=Your E-mail address is public and will be used for any account related notifications, and any web based operations made via the site. profile_desc=Адрес вашей электронной почты является публичным и будет использован для любых уведомлений, связанных с аккаунтом, а также для любых действий, совершенных через сайт.
full_name=ФИО full_name=ФИО
website=Веб-сайт website=Веб-сайт
location=Местоположение location=Местоположение
@ -217,15 +217,15 @@ new_password=Новый пароль
password_incorrect=Текущий пароль не правильный. password_incorrect=Текущий пароль не правильный.
change_password_success=Пароль сменен успешно. Теперь вы можете войти с новым паролем. change_password_success=Пароль сменен успешно. Теперь вы можете войти с новым паролем.
emails=E-mail Addresses emails=Адреса электронной почты
manage_emails=Manage e-mail addresses manage_emails=Управление адресами электронной почты
email_desc=Your primary e-mail address will be used for notifications and other operations. email_desc=Ваш основной адрес электронной почты будет использован для уведомлений и других операций.
primary=Primary primary=Основной
primary_email=Set as primary primary_email=Установить как основной
delete_email=Delete delete_email=Удалить
add_new_email=Add new e-mail address add_new_email=Добавить новый адрес электронной почты
add_email=Add e-mail add_email=Добавить электронную почту
add_email_success=Your new E-mail address was successfully added. add_email_success=Новый адрес электронной почты успешно добавлен.
manage_ssh_keys=Управление SSH ключами manage_ssh_keys=Управление SSH ключами
add_key=Добавить ключ add_key=Добавить ключ
@ -240,20 +240,20 @@ add_on=Добавлено
last_used=Последний раз использовался last_used=Последний раз использовался
no_activity=Еще не применялся no_activity=Еще не применялся
manage_social=Manage Associated Social Accounts manage_social=Управление привязанными учетными записями в соцсетях
social_desc=This is a list of associated social accounts. Remove any binding that you do not recognize. social_desc=Это список привязанных учетных записей в соцсетях. Удаляйте любые неизвестные вам привязки.
unbind=Отвязать unbind=Отвязать
unbind_success=Социальная учетная запись отвязана. unbind_success=Социальная учетная запись отвязана.
manage_access_token=Manage Personal Access Tokens manage_access_token=Управление Токенами Персонального Доступа
generate_new_token=Создать новый token generate_new_token=Создать новый token
tokens_desc=Tokens you have generated that can be used to access the Gogs API. tokens_desc=Созданные вами токены могут использоваться для доступа к Gogs API.
new_token_desc=As for now, every token will have full access to your account. new_token_desc=Пока что каждый токен будет иметь полный доступ к вашей учетной записи.
token_name=Имя маркера token_name=Имя маркера
generate_token=Генерировать маркер generate_token=Генерировать маркер
generate_token_succees=New access token has been generated successfully! Make sure to copy your new personal access token now. You won't be able to see it again! generate_token_succees=Успешно создан новый токен доступа! Пожалуйста сделайте копию вашего нового токена персонального доступа. Вы не сможете увидеть его снова!
delete_token=Удалить delete_token=Удалить
delete_token_success=Personal access token has been deleted successfully! Don't forget to update your applications as well. delete_token_success=Персональный токен доступа был успешно удален! Не забудьте так же обновить ваши приложения.
delete_account=Удалить свой аккаунт delete_account=Удалить свой аккаунт
delete_prompt=Этим действием вы удалите свою учетную запись навсегда и <strong>НЕ СМОЖЕТЕ</strong> ее вернуть! delete_prompt=Этим действием вы удалите свою учетную запись навсегда и <strong>НЕ СМОЖЕТЕ</strong> ее вернуть!
@ -285,7 +285,7 @@ goget_meta_helper=This repository will be <span class="label label-blue label-ra
need_auth=Требуется авторизация need_auth=Требуется авторизация
migrate_type=Тип миграции migrate_type=Тип миграции
migrate_type_helper=Этот репозиторий будет <span class="label label-blue label-radius">зеркалом</span> migrate_type_helper=Этот репозиторий будет <span class="label label-blue label-radius">зеркалом</span>
migrate_repo=Migrate Repository migrate_repo=Перенос репозитория
copy_link=Копировать copy_link=Копировать
click_to_copy=Скопировать в буфер обмена click_to_copy=Скопировать в буфер обмена
@ -322,7 +322,7 @@ commits.author=Автор
commits.message=Сообщение commits.message=Сообщение
commits.date=Дата commits.date=Дата
commits.older=Раньше commits.older=Раньше
commits.newer=Newer commits.newer=Новее
settings=Настройки settings=Настройки
settings.options=Опции settings.options=Опции
@ -347,9 +347,9 @@ settings.transfer_owner=Новый владелец
settings.make_transfer=Выполнить передачу settings.make_transfer=Выполнить передачу
settings.transfer_succeed=Repository ownership has been transferred successfully. settings.transfer_succeed=Repository ownership has been transferred successfully.
settings.confirm_delete=Подтвердить удаление settings.confirm_delete=Подтвердить удаление
settings.add_collaborator=Add New Collaborator settings.add_collaborator=Добавить нового соавтора
settings.add_collaborator_success=New collaborator has been added. settings.add_collaborator_success=Был добавлен новый соавтор.
settings.remove_collaborator_success=Collaborator has been removed. settings.remove_collaborator_success=Соавтор был удален.
settings.user_is_org_member=User is organization member who cannot be added as a collaborator. settings.user_is_org_member=User is organization member who cannot be added as a collaborator.
settings.add_webhook=Добавить Webhook settings.add_webhook=Добавить 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="%s">Webhooks Guide</a>. 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="%s">Webhooks Guide</a>.
@ -462,14 +462,14 @@ members.invite_now=Пригласите сейчас
teams.join=Объединить teams.join=Объединить
teams.leave=Выйти teams.leave=Выйти
teams.read_access=Доступ на чтение teams.read_access=Доступ на чтение
teams.read_access_helper=This team will be able to view and clone its repositories. teams.read_access_helper=Эта команда будет иметь возможность просматривать и клонировать ее репозитории.
teams.write_access=Доступ на запись teams.write_access=Доступ на запись
teams.write_access_helper=This team will be able to read its repositories, as well as push to them. teams.write_access_helper=Эта команда будет в состоянии прочитать ее репозитории, а также посылать изменения.
teams.admin_access=Доступ администратора teams.admin_access=Доступ администратора
teams.admin_access_helper=This team will be able to push/pull to its repositories, as well as add other collaborators to them. teams.admin_access_helper=This team will be able to push/pull to its repositories, as well as add other collaborators to them.
teams.no_desc=Эта группа не имеет описания teams.no_desc=Эта группа не имеет описания
teams.settings=Настройки teams.settings=Настройки
teams.owners_permission_desc=Owners have full access to <strong>all repositories</strong> and have <strong>admin rights</strong> to the organization. teams.owners_permission_desc=Владельцы имеют полный доступ ко <strong>всем репозиториям</strong> и имеют <strong>права администратора</strong> организации.
teams.members=Члены группы разработки teams.members=Члены группы разработки
teams.update_settings=Обновить настройки teams.update_settings=Обновить настройки
teams.delete_team=Удалить эту группу разработки teams.delete_team=Удалить эту группу разработки
@ -486,7 +486,7 @@ teams.remove_repo=Удалить
teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте. teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте.
[admin] [admin]
dashboard=Dashboard dashboard=Панель управления
users=Пользователи users=Пользователи
organizations=Организации organizations=Организации
repositories=Репозитории repositories=Репозитории
@ -508,14 +508,14 @@ dashboard.clean_unbind_oauth=Clean unbound OAuthes
dashboard.clean_unbind_oauth_success=All unbind OAuthes have been deleted successfully. dashboard.clean_unbind_oauth_success=All unbind OAuthes have been deleted successfully.
dashboard.delete_inactivate_accounts=Удалить все неактивированные учетные записи dashboard.delete_inactivate_accounts=Удалить все неактивированные учетные записи
dashboard.delete_inactivate_accounts_success=Все неактивированные учетные записи удалены успешно. dashboard.delete_inactivate_accounts_success=Все неактивированные учетные записи удалены успешно.
dashboard.delete_repo_archives=Delete all repositories archives dashboard.delete_repo_archives=Удаление всех архивов репозиториев
dashboard.delete_repo_archives_success=All repositories archives have been deleted successfully. dashboard.delete_repo_archives_success=Все архивы репозиториев были успешно удалены.
dashboard.git_gc_repos=Do garbage collection on repositories dashboard.git_gc_repos=Выполнить сборку мусора на репозиториях
dashboard.git_gc_repos_success=All repositories have done garbage collection successfully. dashboard.git_gc_repos_success=Сборка мусора на всех репозиториях успешно выполнена.
dashboard.server_uptime=Время непрерывной работы сервера dashboard.server_uptime=Время непрерывной работы сервера
dashboard.current_goroutine=Current Goroutines dashboard.current_goroutine=Current Goroutines
dashboard.current_memory_usage=Текущее использование памяти dashboard.current_memory_usage=Текущее использование памяти
dashboard.total_memory_allocated=Total Memory Allocated dashboard.total_memory_allocated=Всего памяти выделено
dashboard.memory_obtained=Memory Obtained dashboard.memory_obtained=Memory Obtained
dashboard.pointer_lookup_times=Pointer Lookup Times dashboard.pointer_lookup_times=Pointer Lookup Times
dashboard.memory_allocate_times=Memory Allocate Times dashboard.memory_allocate_times=Memory Allocate Times
@ -543,7 +543,7 @@ dashboard.last_gc_pause=Last GC Pause
dashboard.gc_times=GC Times dashboard.gc_times=GC Times
users.user_manage_panel=User Manage Panel users.user_manage_panel=User Manage Panel
users.new_account=Create New Account users.new_account=Создать новый аккаунт
users.name=Имя users.name=Имя
users.activated=Активирован users.activated=Активирован
users.admin=Администратор users.admin=Администратор
@ -560,7 +560,7 @@ users.is_admin=У этой учетной записи есть права ад
users.allow_git_hook=Пользователь имеет право создать Git перехватчик users.allow_git_hook=Пользователь имеет право создать Git перехватчик
users.update_profile=Обновить профиль учетной записи users.update_profile=Обновить профиль учетной записи
users.delete_account=Удалить эту учетную запись users.delete_account=Удалить эту учетную запись
users.still_own_repo=This account still have ownership of repository, you have to delete or transfer them first. users.still_own_repo=На вашем аккаунте все еще остается как минимум один репозиторий, сначала вам нужно удалить или передать его.
users.still_has_org=This account still have membership of organization, you have to left or delete them first. users.still_has_org=This account still have membership of organization, you have to left or delete them first.
orgs.org_manage_panel=Управление группами orgs.org_manage_panel=Управление группами
@ -630,30 +630,30 @@ config.db_path=Path
config.db_path_helper=(for "sqlite3" only) config.db_path_helper=(for "sqlite3" only)
config.service_config=Service Configuration config.service_config=Service Configuration
config.register_email_confirm=Require E-mail Confirmation config.register_email_confirm=Require E-mail Confirmation
config.disable_register=Disable Registration config.disable_register=Отключить регистрацию
config.require_sign_in_view=Require Sign In View config.require_sign_in_view=Для просмотра необходима авторизация
config.mail_notify=Mail Notification config.mail_notify=Почтовые уведомления
config.enable_cache_avatar=Enable Cache Avatar config.enable_cache_avatar=Кешировать аватар
config.active_code_lives=Active Code Lives config.active_code_lives=Active Code Lives
config.reset_password_code_lives=Reset Password Code Lives config.reset_password_code_lives=Reset Password Code Lives
config.webhook_config=Настройка автоматического обновления репозиции config.webhook_config=Настройка автоматического обновления репозиции
config.task_interval=Task Interval config.task_interval=Интервал задания
config.deliver_timeout=Deliver Timeout config.deliver_timeout=Задержка доставки
config.mailer_config=Mailer Configuration config.mailer_config=Настройки почты
config.mailer_enabled=Enabled config.mailer_enabled=Включено
config.mailer_name=Name config.mailer_name=Имя
config.mailer_host=Host config.mailer_host=Сервер
config.mailer_user=User config.mailer_user=Пользователь
config.oauth_config=OAuth Configuration config.oauth_config=Конфигурация OAuth
config.oauth_enabled=Enabled config.oauth_enabled=Включено
config.cache_config=Cache Configuration config.cache_config=Настройки кеша
config.cache_adapter=Cache Adapter config.cache_adapter=Cache Adapter
config.cache_interval=Cache Interval config.cache_interval=Cache Interval
config.cache_conn=Cache Connection config.cache_conn=Cache Connection
config.session_config=Session Configuration config.session_config=Session Configuration
config.session_provider=Session Provider config.session_provider=Session Provider
config.provider_config=Provider Config config.provider_config=Provider Config
config.cookie_name=Cookie Name config.cookie_name=Имя файла cookie
config.enable_set_cookie=Enable Set Cookie config.enable_set_cookie=Enable Set Cookie
config.gc_interval_time=GC Interval Time config.gc_interval_time=GC Interval Time
config.session_life_time=Время жизни сессии config.session_life_time=Время жизни сессии
@ -674,7 +674,7 @@ monitor.execute_times=Execute Times
monitor.process=Запущенные процессы monitor.process=Запущенные процессы
monitor.desc=Описание monitor.desc=Описание
monitor.start=Start Time monitor.start=Start Time
monitor.execute_time=Execution Time monitor.execute_time=Время выполнения
notices.system_notice_list=Система уведомлений notices.system_notice_list=Система уведомлений
notices.type=Тип notices.type=Тип
@ -684,7 +684,7 @@ notices.op=Op.
notices.delete_success=System notice has been deleted successfully. notices.delete_success=System notice has been deleted successfully.
[action] [action]
create_repo=created repository <a href="%s/%s">%s</a> create_repo=создан репозиторий <a href="%s/%s"> %s</a>
commit_repo=pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a> commit_repo=pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a>
create_issue=opened issue <a href="%s/%s/issues/%s">%s#%s</a> create_issue=opened issue <a href="%s/%s/issues/%s">%s#%s</a>
comment_issue=commented on issue <a href="%s/%s/issues/%s">%s#%s</a> comment_issue=commented on issue <a href="%s/%s/issues/%s">%s#%s</a>
@ -703,9 +703,9 @@ now=сейчас
1w=1 week %s 1w=1 week %s
1mon=1 month %s 1mon=1 month %s
1y=1 year %s 1y=1 year %s
seconds=%d seconds %s seconds=%d секунд %s
minutes=%d minutes %s minutes=%d минут %s
hours=%d hours %s hours=%d часов %s
days=%d days %s days=%d days %s
weeks=%d weeks %s weeks=%d weeks %s
months=%d months %s months=%d months %s

View File

@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const APP_VER = "0.5.12.0120 Beta" const APP_VER = "0.5.12.0204 Beta"
func init() { func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

View File

@ -41,12 +41,14 @@ var (
var ( var (
// Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages // Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages
IssueKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"} IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
IssueKeywordsPat *regexp.Regexp IssueCloseKeywordsPat *regexp.Regexp
IssueReferenceKeywordsPat *regexp.Regexp
) )
func init() { func init() {
IssueKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(IssueKeywords, "|"))) IssueCloseKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(IssueCloseKeywords, "|")))
IssueReferenceKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:) \S+`))
} }
// Action represents user operation type and other information to repository., // Action represents user operation type and other information to repository.,
@ -110,13 +112,13 @@ func (a Action) GetIssueInfos() []string {
func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, commits []*base.PushCommit) error { func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, commits []*base.PushCommit) error {
for _, c := range commits { for _, c := range commits {
refs := IssueKeywordsPat.FindAllString(c.Message, -1) references := IssueReferenceKeywordsPat.FindAllString(c.Message, -1)
for _, ref := range refs { for _, ref := range references {
ref := ref[strings.IndexByte(ref, byte(' '))+1:] ref := ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, func(c rune) bool { ref = strings.TrimRightFunc(ref, func(c rune) bool {
return !unicode.IsDigit(c) return !unicode.IsDigit(c)
}) })
if len(ref) == 0 { if len(ref) == 0 {
continue continue
@ -144,6 +146,35 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMIT, message, nil); err != nil { if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMIT, message, nil); err != nil {
return err return err
} }
}
closes := IssueCloseKeywordsPat.FindAllString(c.Message, -1)
for _, ref := range closes {
ref := ref[strings.IndexByte(ref, byte(' '))+1:]
ref = strings.TrimRightFunc(ref, func(c rune) bool {
return !unicode.IsDigit(c)
})
if len(ref) == 0 {
continue
}
// Add repo name if missing
if ref[0] == '#' {
ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref)
} else if strings.Contains(ref, "/") == false {
// We don't support User#ID syntax yet
// return ErrNotImplemented
continue
}
issue, err := GetIssueByRef(ref)
if err != nil {
return err
}
if issue.RepoId == repoId { if issue.RepoId == repoId {
if issue.IsClosed { if issue.IsClosed {
@ -168,6 +199,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
} }
} }
} }
} }
return nil return nil

View File

@ -33,7 +33,7 @@ var (
HasEngine bool HasEngine bool
DbCfg struct { DbCfg struct {
Type, Host, Name, User, Pwd, Path, SslMode string Type, Host, Name, User, Passwd, Path, SSLMode string
} }
EnableSQLite3 bool EnableSQLite3 bool
@ -59,10 +59,10 @@ func LoadModelsConfig() {
DbCfg.Host = sec.Key("HOST").String() DbCfg.Host = sec.Key("HOST").String()
DbCfg.Name = sec.Key("NAME").String() DbCfg.Name = sec.Key("NAME").String()
DbCfg.User = sec.Key("USER").String() DbCfg.User = sec.Key("USER").String()
if len(DbCfg.Pwd) == 0 { if len(DbCfg.Passwd) == 0 {
DbCfg.Pwd = sec.Key("PASSWD").String() DbCfg.Passwd = sec.Key("PASSWD").String()
} }
DbCfg.SslMode = sec.Key("SSL_MODE").String() DbCfg.SSLMode = sec.Key("SSL_MODE").String()
DbCfg.Path = sec.Key("PATH").MustString("data/gogs.db") DbCfg.Path = sec.Key("PATH").MustString("data/gogs.db")
} }
@ -71,7 +71,7 @@ func getEngine() (*xorm.Engine, error) {
switch DbCfg.Type { switch DbCfg.Type {
case "mysql": case "mysql":
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8", cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name) DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
case "postgres": case "postgres":
var host, port = "127.0.0.1", "5432" var host, port = "127.0.0.1", "5432"
fields := strings.Split(DbCfg.Host, ":") fields := strings.Split(DbCfg.Host, ":")
@ -82,7 +82,7 @@ func getEngine() (*xorm.Engine, error) {
port = fields[1] port = fields[1]
} }
cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s", cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode) DbCfg.User, DbCfg.Passwd, host, port, DbCfg.Name, DbCfg.SSLMode)
case "sqlite3": case "sqlite3":
if !EnableSQLite3 { if !EnableSQLite3 {
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type) return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
@ -98,7 +98,7 @@ func getEngine() (*xorm.Engine, error) {
func NewTestEngine(x *xorm.Engine) (err error) { func NewTestEngine(x *xorm.Engine) (err error) {
x, err = getEngine() x, err = getEngine()
if err != nil { if err != nil {
return fmt.Errorf("models.init(fail to connect to database): %v", err) return fmt.Errorf("connect to database: %v", err)
} }
x.SetMapper(core.GonicMapper{}) x.SetMapper(core.GonicMapper{})
@ -108,7 +108,7 @@ func NewTestEngine(x *xorm.Engine) (err error) {
func SetEngine() (err error) { func SetEngine() (err error) {
x, err = getEngine() x, err = getEngine()
if err != nil { if err != nil {
return fmt.Errorf("models.init(fail to connect to database): %v", err) return fmt.Errorf("connect to database: %v", err)
} }
x.SetMapper(core.GonicMapper{}) x.SetMapper(core.GonicMapper{})

View File

@ -33,7 +33,7 @@ const (
) )
var ( var (
ErrKeyAlreadyExist = errors.New("Public key already exist") ErrKeyAlreadyExist = errors.New("Public key already exists")
ErrKeyNotExist = errors.New("Public key does not exist") ErrKeyNotExist = errors.New("Public key does not exist")
ErrKeyUnableVerify = errors.New("Unable to verify public key") ErrKeyUnableVerify = errors.New("Unable to verify public key")
) )
@ -41,7 +41,7 @@ var (
var sshOpLocker = sync.Mutex{} var sshOpLocker = sync.Mutex{}
var ( var (
SshPath string // SSH directory. SSHPath string // SSH directory.
appPath string // Execution(binary) path. appPath string // Execution(binary) path.
) )
@ -72,9 +72,9 @@ func init() {
appPath = strings.Replace(appPath, "\\", "/", -1) appPath = strings.Replace(appPath, "\\", "/", -1)
// Determine and create .ssh path. // Determine and create .ssh path.
SshPath = filepath.Join(homeDir(), ".ssh") SSHPath = filepath.Join(homeDir(), ".ssh")
if err = os.MkdirAll(SshPath, 0700); err != nil { if err = os.MkdirAll(SSHPath, 0700); err != nil {
log.Fatal(4, "fail to create SshPath(%s): %v\n", SshPath, err) log.Fatal(4, "fail to create '%s': %v", SSHPath, err)
} }
} }
@ -244,16 +244,17 @@ func CheckPublicKeyString(content string) (bool, error) {
} }
// saveAuthorizedKeyFile writes SSH key content to authorized_keys file. // saveAuthorizedKeyFile writes SSH key content to authorized_keys file.
func saveAuthorizedKeyFile(key *PublicKey) error { func saveAuthorizedKeyFile(keys ...*PublicKey) error {
sshOpLocker.Lock() sshOpLocker.Lock()
defer sshOpLocker.Unlock() defer sshOpLocker.Unlock()
fpath := filepath.Join(SshPath, "authorized_keys") fpath := filepath.Join(SSHPath, "authorized_keys")
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil { if err != nil {
return err return err
} }
defer f.Close() defer f.Close()
finfo, err := f.Stat() finfo, err := f.Stat()
if err != nil { if err != nil {
return err return err
@ -269,8 +270,12 @@ func saveAuthorizedKeyFile(key *PublicKey) error {
} }
} }
_, err = f.WriteString(key.GetAuthorizedString()) for _, key := range keys {
return err if _, err = f.WriteString(key.GetAuthorizedString()); err != nil {
return err
}
}
return nil
} }
// AddPublicKey adds new public key to database and authorized_keys file. // AddPublicKey adds new public key to database and authorized_keys file.
@ -413,8 +418,8 @@ func DeletePublicKey(key *PublicKey) error {
return err return err
} }
fpath := filepath.Join(SshPath, "authorized_keys") fpath := filepath.Join(SSHPath, "authorized_keys")
tmpPath := filepath.Join(SshPath, "authorized_keys.tmp") tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil { if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
return err return err
} else if err = os.Remove(fpath); err != nil { } else if err = os.Remove(fpath); err != nil {
@ -422,3 +427,37 @@ func DeletePublicKey(key *PublicKey) error {
} }
return os.Rename(tmpPath, fpath) return os.Rename(tmpPath, fpath)
} }
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
func RewriteAllPublicKeys() error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
f, err := os.Create(tmpPath)
if err != nil {
return err
}
defer os.Remove(tmpPath)
err = x.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
_, err = f.WriteString((bean.(*PublicKey)).GetAuthorizedString())
return err
})
f.Close()
if err != nil {
return err
}
fpath := filepath.Join(SSHPath, "authorized_keys")
if com.IsExist(fpath) {
if err = os.Remove(fpath); err != nil {
return err
}
}
if err = os.Rename(tmpPath, fpath); err != nil {
return err
}
return nil
}

View File

@ -7,7 +7,6 @@ package models
import ( import (
"errors" "errors"
"fmt" "fmt"
"html"
"html/template" "html/template"
"io/ioutil" "io/ioutil"
"os" "os"
@ -218,11 +217,9 @@ func (repo *Repository) HasAccess(uname string) bool {
// DescriptionHtml does special handles to description and return HTML string. // DescriptionHtml does special handles to description and return HTML string.
func (repo *Repository) DescriptionHtml() template.HTML { func (repo *Repository) DescriptionHtml() template.HTML {
sanitize := func(s string) string { sanitize := func(s string) string {
// TODO(nuss-justin): Improve sanitization. Strip all tags? return fmt.Sprintf(`<a href="%[1]s" target="_blank">%[1]s</a>`, s)
ss := html.EscapeString(s)
return fmt.Sprintf(`<a href="%s" target="_blank">%s</a>`, ss, ss)
} }
return template.HTML(DescPattern.ReplaceAllStringFunc(base.XSSString(repo.Description), sanitize)) return template.HTML(DescPattern.ReplaceAllStringFunc(base.Sanitizer.Sanitize(repo.Description), sanitize))
} }
// IsRepositoryExist returns true if the repository with given name under user has already existed. // IsRepositoryExist returns true if the repository with given name under user has already existed.
@ -507,6 +504,11 @@ func initRepository(f string, u *User, repo *Repository, initReadme bool, repoLa
} }
if len(fileName) == 0 { if len(fileName) == 0 {
// Re-fetch the repository from database before updating it (else it would
// override changes that were done earlier with sql)
if repo, err = GetRepositoryById(repo.Id); err != nil {
return err
}
repo.IsBare = true repo.IsBare = true
repo.DefaultBranch = "master" repo.DefaultBranch = "master"
return UpdateRepository(repo) return UpdateRepository(repo)

View File

@ -477,6 +477,7 @@ func UpdateUser(u *User) error {
} }
u.Avatar = avatar.HashEmail(u.AvatarEmail) u.Avatar = avatar.HashEmail(u.AvatarEmail)
u.FullName = base.Sanitizer.Sanitize(u.FullName)
_, err = x.Id(u.Id).AllCols().Update(u) _, err = x.Id(u.Id).AllCols().Update(u)
return err return err
} }

View File

@ -9,6 +9,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/Unknwon/com"
"github.com/Unknwon/macaron" "github.com/Unknwon/macaron"
"github.com/macaron-contrib/binding" "github.com/macaron-contrib/binding"
"github.com/macaron-contrib/session" "github.com/macaron-contrib/session"
@ -135,6 +136,10 @@ type Form interface {
binding.Validator binding.Validator
} }
func init() {
binding.SetNameMapper(com.ToSnakeCase)
}
// AssignForm assign form values back to the template data. // AssignForm assign form values back to the template data.
func AssignForm(form interface{}, data map[string]interface{}) { func AssignForm(form interface{}, data map[string]interface{}) {
typ := reflect.TypeOf(form) typ := reflect.TypeOf(form)
@ -152,6 +157,8 @@ func AssignForm(form interface{}, data map[string]interface{}) {
// Allow ignored fields in the struct // Allow ignored fields in the struct
if fieldName == "-" { if fieldName == "-" {
continue continue
} else if len(fieldName) == 0 {
fieldName = com.ToSnakeCase(field.Name)
} }
data[fieldName] = val.Field(i).Interface() data[fieldName] = val.Field(i).Interface()

View File

@ -12,26 +12,27 @@ import (
) )
type InstallForm struct { type InstallForm struct {
Database string `form:"database" binding:"Required"` DbType string `binding:"Required"`
DbHost string `form:"host"` DbHost string
DbUser string `form:"user"` DbUser string
DbPasswd string `form:"passwd"` DbPasswd string
DatabaseName string `form:"database_name"` DbName string
SslMode string `form:"ssl_mode"` SSLMode string
DatabasePath string `form:"database_path"` DbPath string
RepoRootPath string `form:"repo_path" binding:"Required"` RepoRootPath string `binding:"Required"`
RunUser string `form:"run_user" binding:"Required"` RunUser string `binding:"Required"`
Domain string `form:"domain" binding:"Required"` Domain string `binding:"Required"`
AppUrl string `form:"app_url" binding:"Required"` HTTPPort string `binding:"Required"`
SmtpHost string `form:"smtp_host"` AppUrl string `binding:"Required"`
SmtpEmail string `form:"mailer_user"` SMTPHost string
SmtpPasswd string `form:"mailer_pwd"` SMTPEmail string
RegisterConfirm string `form:"register_confirm"` SMTPPasswd string
MailNotify string `form:"mail_notify"` RegisterConfirm string
AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"` MailNotify string
AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(255)"` AdminName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
ConfirmPasswd string `form:"confirm_passwd" binding:"Required;MinSize(6);MaxSize(255)"` AdminPasswd string `binding:"Required;MinSize(6);MaxSize(255)"`
AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"` AdminConfirmPasswd string `binding:"Required;MinSize(6);MaxSize(255)"`
AdminEmail string `binding:"Required;Email;MaxSize(50)"`
} }
func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

View File

@ -63,12 +63,18 @@ func IsImageFile(data []byte) (string, bool) {
return contentType, false return contentType, false
} }
// IsReadmeFile returns true if given file name suppose to be a README file.
func IsReadmeFile(name string) bool { func IsReadmeFile(name string) bool {
name = strings.ToLower(name) name = strings.ToLower(name)
if len(name) < 6 { if len(name) < 6 {
return false return false
} else if len(name) == 6 {
if name == "readme" {
return true
}
return false
} }
if name[:6] == "readme" { if name[:7] == "readme." {
return true return true
} }
return false return false
@ -103,7 +109,7 @@ var (
MentionPattern = regexp.MustCompile(`@[0-9a-zA-Z_]{1,}`) MentionPattern = regexp.MustCompile(`@[0-9a-zA-Z_]{1,}`)
commitPattern = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`) commitPattern = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`)
issueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`) issueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`)
issueIndexPattern = regexp.MustCompile(`#[0-9]+`) issueIndexPattern = regexp.MustCompile(`( |^)#[0-9]+`)
sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`) sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
) )
@ -212,7 +218,7 @@ func RenderRawMarkdown(body []byte, urlPrefix string) []byte {
func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte { func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte {
body := RenderSpecialLink(rawBytes, urlPrefix) body := RenderSpecialLink(rawBytes, urlPrefix)
body = RenderRawMarkdown(body, urlPrefix) body = RenderRawMarkdown(body, urlPrefix)
body = XSS(body) body = Sanitizer.SanitizeBytes(body)
return body return body
} }

View File

@ -13,7 +13,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/microcosm-cc/bluemonday"
"golang.org/x/net/html/charset" "golang.org/x/net/html/charset"
"golang.org/x/text/transform" "golang.org/x/text/transform"
@ -21,11 +20,8 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
// FIXME: use me to Markdown API renders
var p = bluemonday.UGCPolicy()
func Str2html(raw string) template.HTML { func Str2html(raw string) template.HTML {
return template.HTML(p.Sanitize(raw)) return template.HTML(Sanitizer.Sanitize(raw))
} }
func Range(l int) []int { func Range(l int) []int {
@ -90,6 +86,11 @@ func ToUtf8(content string) string {
return res return res
} }
// RenderCommitMessage renders commit message with XSS-safe and special links.
func RenderCommitMessage(msg, urlPrefix string) template.HTML {
return template.HTML(string(RenderIssueIndexPattern([]byte(template.HTMLEscapeString(msg)), urlPrefix)))
}
var mailDomains = map[string]string{ var mailDomains = map[string]string{
"gmail.com": "gmail.com", "gmail.com": "gmail.com",
} }
@ -163,6 +164,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
"EscapePound": func(str string) string { "EscapePound": func(str string) string {
return strings.Replace(str, "#", "%23", -1) return strings.Replace(str, "#", "%23", -1)
}, },
"RenderCommitMessage": RenderCommitMessage,
} }
type Actioner interface { type Actioner interface {

View File

@ -15,17 +15,19 @@ import (
"hash" "hash"
"html/template" "html/template"
"math" "math"
"regexp"
"strings" "strings"
"time" "time"
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/Unknwon/i18n" "github.com/Unknwon/i18n"
"github.com/microcosm-cc/bluemonday"
"github.com/gogits/gogs/modules/avatar" "github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
var Sanitizer = bluemonday.UGCPolicy()
// Encode string to md5 hex value. // Encode string to md5 hex value.
func EncodeMd5(str string) string { func EncodeMd5(str string) string {
m := md5.New() m := md5.New()
@ -473,29 +475,3 @@ func DateFormat(t time.Time, format string) string {
format = replacer.Replace(format) format = replacer.Replace(format)
return t.Format(format) return t.Format(format)
} }
type xssFilter struct {
reg *regexp.Regexp
repl []byte
}
var (
whiteSpace = []byte(" ")
xssFilters = []xssFilter{
{regexp.MustCompile(`\ [ONon]\w*=["]*`), whiteSpace},
{regexp.MustCompile(`<[SCRIPTscript]{6}`), whiteSpace},
{regexp.MustCompile(`=[` + "`" + `'"]*[JAVASCRIPTjavascript \t\0&#x0D;]*:`), whiteSpace},
}
)
// XSS goes through all the XSS filters to make user input content as safe as possible.
func XSS(in []byte) []byte {
for _, filter := range xssFilters {
in = filter.reg.ReplaceAll(in, filter.repl)
}
return in
}
func XSSString(in string) string {
return string(XSS([]byte(in)))
}

View File

@ -54,7 +54,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
if strings.HasSuffix(ctx.Req.RequestURI, "watch") { if strings.HasSuffix(ctx.Req.RequestURI, "watch") {
return return
} }
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl) ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
ctx.Redirect(setting.AppSubUrl + "/user/login") ctx.Redirect(setting.AppSubUrl + "/user/login")
return return
} else if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm { } else if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {

View File

@ -178,7 +178,7 @@ func NewConfigContext() {
log.Fatal(4, "Fail to load custom 'conf/app.ini': %v", err) log.Fatal(4, "Fail to load custom 'conf/app.ini': %v", err)
} }
} else { } else {
log.Warn("No custom 'conf/app.ini' found, please go to '/install'") log.Warn("No custom 'conf/app.ini' found, ignore this if you're running first time")
} }
Cfg.NameMapper = ini.AllCapsUnderscore Cfg.NameMapper = ini.AllCapsUnderscore

View File

@ -1052,22 +1052,6 @@ function initRepoSetting() {
return; return;
} }
Gogits.getUsers($this.val(), $this.next()); Gogits.getUsers($this.val(), $this.next());
/*$.ajax({
url: '/api/v1/users/search?q=' + $this.val(),
dataType: "json",
success: function (json) {
if (json.ok && json.data.length) {
var html = '';
$.each(json.data, function (i, item) {
html += '<li><img src="' + item.avatar + '">' + item.username + '</li>';
});
$this.next().toggleShow();
$this.next().find('ul').html(html);
} else {
$this.next().toggleHide();
}
}
});*/
}).on('focus', function () { }).on('focus', function () {
if (!$(this).val()) { if (!$(this).val()) {
$(this).next().toggleHide(); $(this).next().toggleHide();

View File

@ -1630,6 +1630,10 @@ The register and sign-in page style
background-color: #d1ffd6 !important; background-color: #d1ffd6 !important;
border-color: #b4e2b4 !important; border-color: #b4e2b4 !important;
} }
.diff-file-box .code-diff tbody tr.add-code td.selected-line,
.diff-file-box .code-diff tbody tr.add-code td.selected-line pre {
background-color: #ffffdd !important;
}
.diff-file-box .code-diff tbody tr:hover td, .diff-file-box .code-diff tbody tr:hover td,
.diff-file-box .code-diff tbody tr:hover pre { .diff-file-box .code-diff tbody tr:hover pre {
background-color: #FFF8D2 !important; background-color: #FFF8D2 !important;
@ -1761,6 +1765,7 @@ The register and sign-in page style
#org-setting-form, #org-setting-form,
#repo-setting-form, #repo-setting-form,
#user-profile-form, #user-profile-form,
#add-email-form,
.repo-setting-form { .repo-setting-form {
background-color: #FFF; background-color: #FFF;
padding: 30px 0; padding: 30px 0;
@ -1769,6 +1774,7 @@ The register and sign-in page style
#org-setting-form textarea, #org-setting-form textarea,
#repo-setting-form textarea, #repo-setting-form textarea,
#user-profile-form textarea, #user-profile-form textarea,
#add-email-form textarea,
.repo-setting-form textarea { .repo-setting-form textarea {
margin-left: 4px; margin-left: 4px;
height: 100px; height: 100px;
@ -1777,11 +1783,13 @@ The register and sign-in page style
#org-setting-form label, #org-setting-form label,
#repo-setting-form label, #repo-setting-form label,
#user-profile-form label, #user-profile-form label,
#add-email-form label,
.repo-setting-form label, .repo-setting-form label,
#auth-setting-form .form-label, #auth-setting-form .form-label,
#org-setting-form .form-label, #org-setting-form .form-label,
#repo-setting-form .form-label, #repo-setting-form .form-label,
#user-profile-form .form-label, #user-profile-form .form-label,
#add-email-form .form-label,
.repo-setting-form .form-label { .repo-setting-form .form-label {
width: 240px; width: 240px;
} }
@ -1789,6 +1797,7 @@ The register and sign-in page style
#org-setting-form .ipt, #org-setting-form .ipt,
#repo-setting-form .ipt, #repo-setting-form .ipt,
#user-profile-form .ipt, #user-profile-form .ipt,
#add-email-form .ipt,
.repo-setting-form .ipt { .repo-setting-form .ipt {
width: 360px; width: 360px;
} }
@ -1796,6 +1805,7 @@ The register and sign-in page style
#org-setting-form .field, #org-setting-form .field,
#repo-setting-form .field, #repo-setting-form .field,
#user-profile-form .field, #user-profile-form .field,
#add-email-form .field,
.repo-setting-form .field { .repo-setting-form .field {
margin-bottom: 24px; margin-bottom: 24px;
} }
@ -1813,6 +1823,7 @@ The register and sign-in page style
#repo-hooks-history-panel, #repo-hooks-history-panel,
#user-social-panel, #user-social-panel,
#user-applications-panel, #user-applications-panel,
#user-email-panel,
#user-ssh-panel { #user-ssh-panel {
margin-bottom: 20px; margin-bottom: 20px;
} }
@ -1820,6 +1831,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list, #repo-hooks-history-panel .setting-list,
#user-social-panel .setting-list, #user-social-panel .setting-list,
#user-applications-panel .setting-list, #user-applications-panel .setting-list,
#user-email-panel .setting-list,
#user-ssh-panel .setting-list { #user-ssh-panel .setting-list {
background-color: #FFF; background-color: #FFF;
} }
@ -1827,6 +1839,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list li, #repo-hooks-history-panel .setting-list li,
#user-social-panel .setting-list li, #user-social-panel .setting-list li,
#user-applications-panel .setting-list li, #user-applications-panel .setting-list li,
#user-email-panel .setting-list li,
#user-ssh-panel .setting-list li { #user-ssh-panel .setting-list li {
padding: 8px 20px; padding: 8px 20px;
border-bottom: 1px solid #eaeaea; border-bottom: 1px solid #eaeaea;
@ -1835,6 +1848,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list li.ssh:hover, #repo-hooks-history-panel .setting-list li.ssh:hover,
#user-social-panel .setting-list li.ssh:hover, #user-social-panel .setting-list li.ssh:hover,
#user-applications-panel .setting-list li.ssh:hover, #user-applications-panel .setting-list li.ssh:hover,
#user-email-panel .setting-list li.ssh:hover,
#user-ssh-panel .setting-list li.ssh:hover { #user-ssh-panel .setting-list li.ssh:hover {
background-color: #ffffEE; background-color: #ffffEE;
} }
@ -1842,6 +1856,7 @@ The register and sign-in page style
#repo-hooks-history-panel .setting-list li i, #repo-hooks-history-panel .setting-list li i,
#user-social-panel .setting-list li i, #user-social-panel .setting-list li i,
#user-applications-panel .setting-list li i, #user-applications-panel .setting-list li i,
#user-email-panel .setting-list li i,
#user-ssh-panel .setting-list li i { #user-ssh-panel .setting-list li i {
padding-right: 5px; padding-right: 5px;
} }
@ -1849,6 +1864,7 @@ The register and sign-in page style
#repo-hooks-history-panel .active-icon, #repo-hooks-history-panel .active-icon,
#user-social-panel .active-icon, #user-social-panel .active-icon,
#user-applications-panel .active-icon, #user-applications-panel .active-icon,
#user-email-panel .active-icon,
#user-ssh-panel .active-icon { #user-ssh-panel .active-icon {
width: 10px; width: 10px;
height: 10px; height: 10px;
@ -1861,6 +1877,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content, #repo-hooks-history-panel .ssh-content,
#user-social-panel .ssh-content, #user-social-panel .ssh-content,
#user-applications-panel .ssh-content, #user-applications-panel .ssh-content,
#user-email-panel .ssh-content,
#user-ssh-panel .ssh-content { #user-ssh-panel .ssh-content {
margin-left: 24px; margin-left: 24px;
} }
@ -1868,6 +1885,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content .octicon, #repo-hooks-history-panel .ssh-content .octicon,
#user-social-panel .ssh-content .octicon, #user-social-panel .ssh-content .octicon,
#user-applications-panel .ssh-content .octicon, #user-applications-panel .ssh-content .octicon,
#user-email-panel .ssh-content .octicon,
#user-ssh-panel .ssh-content .octicon { #user-ssh-panel .ssh-content .octicon {
margin-right: 4px; margin-right: 4px;
} }
@ -1875,16 +1893,19 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content .print, #repo-hooks-history-panel .ssh-content .print,
#user-social-panel .ssh-content .print, #user-social-panel .ssh-content .print,
#user-applications-panel .ssh-content .print, #user-applications-panel .ssh-content .print,
#user-email-panel .ssh-content .print,
#user-ssh-panel .ssh-content .print, #user-ssh-panel .ssh-content .print,
#repo-hooks-panel .ssh-content .access, #repo-hooks-panel .ssh-content .access,
#repo-hooks-history-panel .ssh-content .access, #repo-hooks-history-panel .ssh-content .access,
#user-social-panel .ssh-content .access, #user-social-panel .ssh-content .access,
#user-applications-panel .ssh-content .access, #user-applications-panel .ssh-content .access,
#user-email-panel .ssh-content .access,
#user-ssh-panel .ssh-content .access, #user-ssh-panel .ssh-content .access,
#repo-hooks-panel .ssh-content .activity, #repo-hooks-panel .ssh-content .activity,
#repo-hooks-history-panel .ssh-content .activity, #repo-hooks-history-panel .ssh-content .activity,
#user-social-panel .ssh-content .activity, #user-social-panel .ssh-content .activity,
#user-applications-panel .ssh-content .activity, #user-applications-panel .ssh-content .activity,
#user-email-panel .ssh-content .activity,
#user-ssh-panel .ssh-content .activity { #user-ssh-panel .ssh-content .activity {
color: #888; color: #888;
} }
@ -1892,6 +1913,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-content .access, #repo-hooks-history-panel .ssh-content .access,
#user-social-panel .ssh-content .access, #user-social-panel .ssh-content .access,
#user-applications-panel .ssh-content .access, #user-applications-panel .ssh-content .access,
#user-email-panel .ssh-content .access,
#user-ssh-panel .ssh-content .access { #user-ssh-panel .ssh-content .access {
max-width: 500px; max-width: 500px;
} }
@ -1899,6 +1921,7 @@ The register and sign-in page style
#repo-hooks-history-panel .ssh-btn, #repo-hooks-history-panel .ssh-btn,
#user-social-panel .ssh-btn, #user-social-panel .ssh-btn,
#user-applications-panel .ssh-btn, #user-applications-panel .ssh-btn,
#user-email-panel .ssh-btn,
#user-ssh-panel .ssh-btn { #user-ssh-panel .ssh-btn {
margin-top: 6px; margin-top: 6px;
} }

View File

@ -202,6 +202,78 @@ var Gogs = {};
}).trigger('hashchange'); }).trigger('hashchange');
}; };
// Render diff view.
Gogs.renderDiffView = function () {
function selectRange($list, $select, $from) {
$list.removeClass('active');
$list.parents('tr').find('td').removeClass('selected-line');
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('[rel=L' + i + ']');
}
$list.filter(classes.join(',')).addClass('active');
$list.filter(classes.join(',')).parents('tr').find('td').addClass('selected-line');
$.changeHash('#L' + a + '-' + 'L' + b);
return
}
}
$select.addClass('active');
$select.parents('tr').find('td').addClass('selected-line');
$.changeHash('#' + $select.attr('rel'));
}
$(document).on('click', '.code-diff .lines-num span', function (e) {
var $select = $(this);
var $list = $select.parent().siblings('.lines-code').parents().find('td.lines-num > span');
selectRange(
$list,
$list.filter('[rel=' + $select.attr('rel') + ']'),
(e.shiftKey && $list.filter('.active').length ? $list.filter('.active').eq(0) : null)
);
$.deSelect();
});
$('.code-diff .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-diff td.lines-num > span');
var $first;
if (m) {
$first = $list.filter('[rel=' + m[1] + ']');
selectRange($list, $first, $list.filter('[rel=' + m[2] + ']'));
$("html, body").scrollTop($first.offset().top - 200);
return;
}
m = window.location.hash.match(/^#(L\d+)$/);
if (m) {
$first = $list.filter('[rel=' + m[1] + ']');
selectRange($list, $first);
$("html, body").scrollTop($first.offset().top - 200);
}
}).trigger('hashchange');
};
// Search users by keyword. // Search users by keyword.
Gogs.searchUsers = function (val, $target) { Gogs.searchUsers = function (val, $target) {
var notEmpty = function (str) { var notEmpty = function (str) {
@ -287,7 +359,12 @@ var Gogs = {};
function initCore() { function initCore() {
Gogs.renderMarkdown(); Gogs.renderMarkdown();
Gogs.renderCodeView();
if ($('.code-diff').length == 0) {
Gogs.renderCodeView();
} else {
Gogs.renderDiffView();
}
// Switch list. // Switch list.
$('.js-tab-nav').click(function (e) { $('.js-tab-nav').click(function (e) {
@ -508,7 +585,7 @@ function initRepoSetting() {
$ul.toggleShow(); $ul.toggleShow();
} }
}).next().next().find('ul').on("click", 'li', function () { }).next().next().find('ul').on("click", 'li', function () {
$('#repo-collaborator').val($(this).text()); $('#repo-collaborator').val($(this).find('.username').text());
$ul.toggleHide(); $ul.toggleHide();
}); });
} }
@ -608,7 +685,7 @@ function initTeamMembersList() {
$ul.toggleShow(); $ul.toggleShow();
} }
}).next().next().find('ul').on("click", 'li', function () { }).next().next().find('ul').on("click", 'li', function () {
$('#org-team-members-add').val($(this).text()); $('#org-team-members-add').val($(this).find('.username').text());
$ul.toggleHide(); $ul.toggleHide();
}); });
} }

File diff suppressed because one or more lines are too long

View File

@ -665,6 +665,9 @@
background-color: #d1ffd6 !important; background-color: #d1ffd6 !important;
border-color: #b4e2b4 !important; border-color: #b4e2b4 !important;
} }
td.selected-line, td.selected-line pre {
background-color: #ffffdd !important;
}
} }
&:hover { &:hover {
td, pre { td, pre {

View File

@ -35,6 +35,7 @@
#org-setting-form, #org-setting-form,
#repo-setting-form, #repo-setting-form,
#user-profile-form, #user-profile-form,
#add-email-form,
.repo-setting-form { .repo-setting-form {
background-color: #FFF; background-color: #FFF;
padding: 30px 0; padding: 30px 0;
@ -69,6 +70,7 @@
#repo-hooks-history-panel, #repo-hooks-history-panel,
#user-social-panel, #user-social-panel,
#user-applications-panel, #user-applications-panel,
#user-email-panel,
#user-ssh-panel { #user-ssh-panel {
margin-bottom: 20px; margin-bottom: 20px;
.setting-list { .setting-list {

View File

@ -118,6 +118,7 @@ const (
CLEAN_INACTIVATE_USER CLEAN_INACTIVATE_USER
CLEAN_REPO_ARCHIVES CLEAN_REPO_ARCHIVES
GIT_GC_REPOS GIT_GC_REPOS
SYNC_SSH_AUTHORIZED_KEY
) )
func Dashboard(ctx *middleware.Context) { func Dashboard(ctx *middleware.Context) {
@ -144,6 +145,9 @@ func Dashboard(ctx *middleware.Context) {
case GIT_GC_REPOS: case GIT_GC_REPOS:
success = ctx.Tr("admin.dashboard.git_gc_repos_success") success = ctx.Tr("admin.dashboard.git_gc_repos_success")
err = models.GitGcRepos() err = models.GitGcRepos()
case SYNC_SSH_AUTHORIZED_KEY:
success = ctx.Tr("admin.dashboard.resync_all_sshkeys_success")
err = models.RewriteAllPublicKeys()
} }
if err != nil { if err != nil {

View File

@ -14,6 +14,7 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/Unknwon/macaron" "github.com/Unknwon/macaron"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"gopkg.in/ini.v1"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/auth"
@ -73,12 +74,7 @@ func GlobalInit() {
checkRunMode() checkRunMode()
} }
func renderDbOption(ctx *middleware.Context) { func InstallInit(ctx *middleware.Context) {
ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
}
// @router /install [get]
func Install(ctx *middleware.Context, form auth.InstallForm) {
if setting.InstallLock { if setting.InstallLock {
ctx.Handle(404, "Install", errors.New("Installation is prohibited")) ctx.Handle(404, "Install", errors.New("Installation is prohibited"))
return return
@ -87,46 +83,35 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
ctx.Data["Title"] = ctx.Tr("install.install") ctx.Data["Title"] = ctx.Tr("install.install")
ctx.Data["PageIsInstall"] = true ctx.Data["PageIsInstall"] = true
// FIXME: when i'm ckeching length here? should they all be 0 no matter when? ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
// Get and assign values to install form. }
if len(form.DbHost) == 0 {
form.DbHost = models.DbCfg.Host
}
if len(form.DbUser) == 0 {
form.DbUser = models.DbCfg.User
}
if len(form.DbPasswd) == 0 {
form.DbPasswd = models.DbCfg.Pwd
}
if len(form.DatabaseName) == 0 {
form.DatabaseName = models.DbCfg.Name
}
if len(form.DatabasePath) == 0 {
form.DatabasePath = models.DbCfg.Path
}
if len(form.RepoRootPath) == 0 { func Install(ctx *middleware.Context) {
form.RepoRootPath = setting.RepoRootPath form := auth.InstallForm{}
}
if len(form.RunUser) == 0 { form.DbHost = models.DbCfg.Host
// Note: it's not normall to use SSH in windows so current user can be first option(not git). form.DbUser = models.DbCfg.User
if setting.IsWindows && setting.RunUser == "git" { form.DbPasswd = models.DbCfg.Passwd
form.RunUser = os.Getenv("USER") form.DbName = models.DbCfg.Name
if len(form.RunUser) == 0 { form.DbPath = models.DbCfg.Path
form.RunUser = os.Getenv("USERNAME")
} form.RepoRootPath = setting.RepoRootPath
} else {
form.RunUser = setting.RunUser // Note(unknwon): it's hard for Windows users change a running user,
// so just use current one if config says default.
if setting.IsWindows && setting.RunUser == "git" {
form.RunUser = os.Getenv("USER")
if len(form.RunUser) == 0 {
form.RunUser = os.Getenv("USERNAME")
} }
} } else {
if len(form.Domain) == 0 { form.RunUser = setting.RunUser
form.Domain = setting.Domain
}
if len(form.AppUrl) == 0 {
form.AppUrl = setting.AppUrl
} }
renderDbOption(ctx) form.Domain = setting.Domain
form.HTTPPort = setting.HttpPort
form.AppUrl = setting.AppUrl
curDbOp := "" curDbOp := ""
if models.EnableSQLite3 { if models.EnableSQLite3 {
curDbOp = "SQLite3" // Default when enabled. curDbOp = "SQLite3" // Default when enabled.
@ -138,16 +123,7 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
} }
func InstallPost(ctx *middleware.Context, form auth.InstallForm) { func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
if setting.InstallLock { ctx.Data["CurDbOption"] = form.DbType
ctx.Handle(404, "InstallPost", errors.New("Installation is prohibited"))
return
}
ctx.Data["Title"] = ctx.Tr("install.install")
ctx.Data["PageIsInstall"] = true
renderDbOption(ctx)
ctx.Data["CurDbOption"] = form.Database
if ctx.HasError() { if ctx.HasError() {
ctx.HTML(200, INSTALL) ctx.HTML(200, INSTALL)
@ -162,18 +138,17 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
// Pass basic check, now test configuration. // Pass basic check, now test configuration.
// Test database setting. // Test database setting.
dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3"} dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3"}
models.DbCfg.Type = dbTypes[form.Database] models.DbCfg.Type = dbTypes[form.DbType]
models.DbCfg.Host = form.DbHost models.DbCfg.Host = form.DbHost
models.DbCfg.User = form.DbUser models.DbCfg.User = form.DbUser
models.DbCfg.Pwd = form.DbPasswd models.DbCfg.Passwd = form.DbPasswd
models.DbCfg.Name = form.DatabaseName models.DbCfg.Name = form.DbName
models.DbCfg.SslMode = form.SslMode models.DbCfg.SSLMode = form.SSLMode
models.DbCfg.Path = form.DatabasePath models.DbCfg.Path = form.DbPath
// Set test engine. // Set test engine.
var x *xorm.Engine var x *xorm.Engine
if err := models.NewTestEngine(x); err != nil { if err := models.NewTestEngine(x); err != nil {
// FIXME: should use core.QueryDriver (github.com/go-xorm/core)
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) { if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "http://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &form) ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "http://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &form)
} else { } else {
@ -194,7 +169,6 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
if len(curUser) == 0 { if len(curUser) == 0 {
curUser = os.Getenv("USERNAME") curUser = os.Getenv("USERNAME")
} }
// Does not check run user when the install lock is off.
if form.RunUser != curUser { if form.RunUser != curUser {
ctx.Data["Err_RunUser"] = true ctx.Data["Err_RunUser"] = true
ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", form.RunUser, curUser), INSTALL, &form) ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", form.RunUser, curUser), INSTALL, &form)
@ -202,47 +176,53 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
} }
// Check admin password. // Check admin password.
if form.AdminPasswd != form.ConfirmPasswd { if form.AdminPasswd != form.AdminConfirmPasswd {
ctx.Data["Err_AdminPasswd"] = true ctx.Data["Err_AdminPasswd"] = true
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), INSTALL, form) ctx.RenderWithErr(ctx.Tr("form.password_not_match"), INSTALL, form)
return return
} }
// Save settings. if form.AppUrl[len(form.AppUrl)-1] != '/' {
setting.Cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type) form.AppUrl += "/"
setting.Cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
setting.Cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
setting.Cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
setting.Cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Pwd)
setting.Cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SslMode)
setting.Cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
setting.Cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
setting.Cfg.Section("").Key("RUN_USER").SetValue(form.RunUser)
setting.Cfg.Section("server").Key("DOMAIN").SetValue(form.Domain)
setting.Cfg.Section("server").Key("ROOT_URL").SetValue(form.AppUrl)
if len(strings.TrimSpace(form.SmtpHost)) > 0 {
setting.Cfg.Section("mailer").Key("ENABLED").SetValue("true")
setting.Cfg.Section("mailer").Key("HOST").SetValue(form.SmtpHost)
setting.Cfg.Section("mailer").Key("USER").SetValue(form.SmtpEmail)
setting.Cfg.Section("mailer").Key("PASSWD").SetValue(form.SmtpPasswd)
setting.Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(form.RegisterConfirm == "on"))
setting.Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(form.MailNotify == "on"))
} }
setting.Cfg.Section("").Key("RUN_MODE").SetValue("prod") // Save settings.
cfg := ini.Empty()
cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd)
cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode)
cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
setting.Cfg.Section("session").Key("PROVIDER").SetValue("file") cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
cfg.Section("").Key("RUN_USER").SetValue(form.RunUser)
cfg.Section("server").Key("DOMAIN").SetValue(form.Domain)
cfg.Section("server").Key("HTTP_PORT").SetValue(form.HTTPPort)
cfg.Section("server").Key("ROOT_URL").SetValue(form.AppUrl)
setting.Cfg.Section("log").Key("MODE").SetValue("file") if len(strings.TrimSpace(form.SMTPHost)) > 0 {
cfg.Section("mailer").Key("ENABLED").SetValue("true")
cfg.Section("mailer").Key("HOST").SetValue(form.SMTPHost)
cfg.Section("mailer").Key("USER").SetValue(form.SMTPEmail)
cfg.Section("mailer").Key("PASSWD").SetValue(form.SMTPPasswd)
setting.Cfg.Section("security").Key("INSTALL_LOCK").SetValue("true") cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(form.RegisterConfirm == "on"))
setting.Cfg.Section("security").Key("SECRET_KEY").SetValue(base.GetRandomString(15)) cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(form.MailNotify == "on"))
}
cfg.Section("").Key("RUN_MODE").SetValue("prod")
cfg.Section("session").Key("PROVIDER").SetValue("file")
cfg.Section("log").Key("MODE").SetValue("file")
cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
cfg.Section("security").Key("SECRET_KEY").SetValue(base.GetRandomString(15))
os.MkdirAll("custom/conf", os.ModePerm) os.MkdirAll("custom/conf", os.ModePerm)
if err := setting.Cfg.SaveTo(path.Join(setting.CustomPath, "conf/app.ini")); err != nil { if err := cfg.SaveTo(path.Join(setting.CustomPath, "conf/app.ini")); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), INSTALL, &form) ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), INSTALL, &form)
return return
} }
@ -264,5 +244,5 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
log.Info("First-time run install finished!") log.Info("First-time run install finished!")
ctx.Flash.Success(ctx.Tr("install.install_success")) ctx.Flash.Success(ctx.Tr("install.install_success"))
ctx.Redirect(setting.AppSubUrl + "/user/login") ctx.Redirect(form.AppUrl + "user/login")
} }

View File

@ -37,7 +37,7 @@ func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List {
newCommits := list.New() newCommits := list.New()
for e := oldCommits.Front(); e != nil; e = e.Next() { for e := oldCommits.Front(); e != nil; e = e.Next() {
c := e.Value.(*git.Commit) c := e.Value.(*git.Commit)
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), repoLink)) c.CommitMessage = c.CommitMessage
newCommits.PushBack(c) newCommits.PushBack(c)
} }
return newCommits return newCommits
@ -206,7 +206,7 @@ func Diff(ctx *middleware.Context) {
commitId := ctx.Repo.CommitId commitId := ctx.Repo.CommitId
commit := ctx.Repo.Commit commit := ctx.Repo.Commit
commit.CommitMessage = string(base.RenderIssueIndexPattern([]byte(commit.CommitMessage), ctx.Repo.RepoLink)) commit.CommitMessage = commit.CommitMessage
diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName), diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName),
commitId, setting.Git.MaxGitDiffLines) commitId, setting.Git.MaxGitDiffLines)
if err != nil { if err != nil {

View File

@ -25,16 +25,16 @@ func ServeBlob(ctx *middleware.Context, blob *git.Blob) error {
buf = buf[:n] buf = buf[:n]
} }
contentType, isTextFile := base.IsTextFile(buf) _, isTextFile := base.IsTextFile(buf)
_, isImageFile := base.IsImageFile(buf) _, isImageFile := base.IsImageFile(buf)
ctx.Resp.Header().Set("Content-Type", contentType) ctx.Resp.Header().Set("Content-Type", "text/plain")
if !isTextFile && !isImageFile { if !isTextFile && !isImageFile {
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+path.Base(ctx.Repo.TreeName)) ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+path.Base(ctx.Repo.TreeName))
ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary") ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
} }
ctx.Resp.Write(buf) ctx.Resp.Write(buf)
io.Copy(ctx.Resp, dataRc) _, err = io.Copy(ctx.Resp, dataRc)
return nil return err
} }
func SingleDownload(ctx *middleware.Context) { func SingleDownload(ctx *middleware.Context) {

View File

@ -156,9 +156,9 @@ func Home(ctx *middleware.Context) {
for _, f := range files { for _, f := range files {
switch c := f[1].(type) { switch c := f[1].(type) {
case *git.Commit: case *git.Commit:
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), ctx.Repo.RepoLink)) c.CommitMessage = c.CommitMessage
case *git.SubModuleFile: case *git.SubModuleFile:
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), ctx.Repo.RepoLink)) c.CommitMessage = c.CommitMessage
} }
} }
ctx.Data["Files"] = files ctx.Data["Files"] = files

46
scripts/init/freebsd/gogs Normal file
View File

@ -0,0 +1,46 @@
#!/bin/sh
#
# $FreeBSD$
#
# PROVIDE: gogs
# REQUIRE: NETWORKING SYSLOG
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf to enable gogs:
#
#gogs_enable="YES"
. /etc/rc.subr
name="gogs"
rcvar="gogs_enable"
load_rc_config $name
: ${gogs_user:="git"}
: ${gogs_enable:="NO"}
: ${gogs_directory:="/home/git"}
command="${gogs_directory}/scripts/start.sh"
pidfile="${gogs_directory}/${name}.pid"
start_cmd="${name}_start"
stop_cmd="${name}_stop"
gogs_start() {
cd ${gogs_directory}
export USER=${gogs_user}
export HOME=${gogs_directory}
/usr/sbin/daemon -f -u ${gogs_user} -p ${pidfile} $command
}
gogs_stop() {
if [ ! -f $pidfile ]; then
echo "GOGS PID File not found. Maybe GOGS is not running?"
else
kill $(cat $pidfile)
fi
}
run_rc_command "$1"

View File

@ -1,2 +0,0 @@
@echo off
..\\gogs.exe web

View File

@ -3,7 +3,7 @@
# Use of this source code is governed by a MIT-style # Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file. # license that can be found in the LICENSE file.
# #
# start gogs web # MUST EXECUTE THIS AT ROOT DIRECTORY: ./scripts/start.sh
# #
IFS=' IFS='
' '

View File

@ -1 +1 @@
0.5.12.0120 Beta 0.5.12.0204 Beta

View File

@ -61,7 +61,7 @@
<dt>{{.i18n.Tr "admin.config.db_user"}}</dt> <dt>{{.i18n.Tr "admin.config.db_user"}}</dt>
<dd>{{.DbCfg.User}}</dd> <dd>{{.DbCfg.User}}</dd>
<dt>{{.i18n.Tr "admin.config.db_ssl_mode"}}</dt> <dt>{{.i18n.Tr "admin.config.db_ssl_mode"}}</dt>
<dd>{{.DbCfg.SslMode}} {{.i18n.Tr "admin.config.db_ssl_mode_helper"}}</dd> <dd>{{.DbCfg.SSLMode}} {{.i18n.Tr "admin.config.db_ssl_mode_helper"}}</dd>
<dt>{{.i18n.Tr "admin.config.db_path"}}</dt> <dt>{{.i18n.Tr "admin.config.db_path"}}</dt>
<dd>{{.DbCfg.Path}} {{.i18n.Tr "admin.config.db_path_helper"}}</dd> <dd>{{.DbCfg.Path}} {{.i18n.Tr "admin.config.db_path_helper"}}</dd>
</dl> </dl>

View File

@ -48,6 +48,11 @@
<td>{{.i18n.Tr "admin.dashboard.git_gc_repos"}}</td> <td>{{.i18n.Tr "admin.dashboard.git_gc_repos"}}</td>
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=4">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=4">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
</tr> </tr>
<tr>
<td>{{.i18n.Tr "admin.dashboard.resync_all_sshkeys"}}</td>
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=5">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -28,7 +28,7 @@
<div class="grid-1-2 left"> <div class="grid-1-2 left">
<i class="octicon octicon-flame"></i> <i class="octicon octicon-flame"></i>
<b>Einfach zu installieren</b> <b>Einfach zu installieren</b>
<p>Starte einfach <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">die Anwendung</a> für deine Plattform. Gogs gibt es auch für <a target="_blank" href="https://github.com/gogits/gogs/tree/master/dockerfiles">Docker</a>, <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a> oder als <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">Installationspaket</a>.</p> <p>Starte einfach <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">die Anwendung</a> für deine Plattform. Gogs gibt es auch für <a target="_blank" href="https://github.com/gogits/gogs/tree/master/docker">Docker</a>, <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a> oder als <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">Installationspaket</a>.</p>
</div> </div>
<div class="grid-1-2 left"> <div class="grid-1-2 left">
<i class="octicon octicon-device-desktop"></i> <i class="octicon octicon-device-desktop"></i>
@ -49,7 +49,7 @@
<div class="grid-1-2 left"> <div class="grid-1-2 left">
<i class="octicon octicon-flame"></i> <i class="octicon octicon-flame"></i>
<b>易安装</b> <b>易安装</b>
<p>您除了可以根据操作系统平台通过 <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">二进制运行</a>,还可以通过 <a target="_blank" href="https://github.com/gogits/gogs/tree/master/dockerfiles">Docker</a> 或 <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>,以及 <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">包管理</a> 安装。</p> <p>您除了可以根据操作系统平台通过 <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">二进制运行</a>,还可以通过 <a target="_blank" href="https://github.com/gogits/gogs/tree/master/docker">Docker</a> 或 <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>,以及 <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">包管理</a> 安装。</p>
</div> </div>
<div class="grid-1-2 left"> <div class="grid-1-2 left">
<i class="octicon octicon-device-desktop"></i> <i class="octicon octicon-device-desktop"></i>
@ -70,7 +70,7 @@
<div class="grid-1-2 left"> <div class="grid-1-2 left">
<i class="octicon octicon-flame"></i> <i class="octicon octicon-flame"></i>
<b>Easy to install</b> <b>Easy to install</b>
<p>Simply <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">run the binary</a> for your platform. Or ship Gogs with <a target="_blank" href="https://github.com/gogits/gogs/tree/master/dockerfiles">Docker</a> or <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>, or get it <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">packaged</a>.</p> <p>Simply <a target="_blank" href="http://gogs.io/docs/installation/install_from_binary.html">run the binary</a> for your platform. Or ship Gogs with <a target="_blank" href="https://github.com/gogits/gogs/tree/master/docker">Docker</a> or <a target="_blank" href="https://github.com/geerlingguy/ansible-vagrant-examples/tree/master/gogs">Vagrant</a>, or get it <a target="_blank" href="http://gogs.io/docs/installation/install_from_packages.html">packaged</a>.</p>
</div> </div>
<div class="grid-1-2 left"> <div class="grid-1-2 left">
<i class="octicon octicon-device-desktop"></i> <i class="octicon octicon-device-desktop"></i>

View File

@ -13,7 +13,7 @@
<div class="text-center panel-desc">{{.i18n.Tr "install.requite_db_desc"}}</div> <div class="text-center panel-desc">{{.i18n.Tr "install.requite_db_desc"}}</div>
<div class="field"> <div class="field">
<label class="req">{{.i18n.Tr "install.db_type"}}</label> <label class="req">{{.i18n.Tr "install.db_type"}}</label>
<select name="database" id="install-database" class="form-control"> <select name="db_type" id="install-database" class="form-control">
{{range .DbOptions}} {{range .DbOptions}}
<option value="{{.}}"{{if eq $.CurDbOption .}}selected{{end}}>{{.}}</option> <option value="{{.}}"{{if eq $.CurDbOption .}}selected{{end}}>{{.}}</option>
{{end}} {{end}}
@ -22,20 +22,20 @@
<div class="server-sql {{if eq .CurDbOption "SQLite3"}}hide{{end}}"> <div class="server-sql {{if eq .CurDbOption "SQLite3"}}hide{{end}}">
<div class="field"> <div class="field">
<label class="req" for="host">{{.i18n.Tr "install.host"}}</label> <label class="req" for="db_host">{{.i18n.Tr "install.host"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbHost}}ipt-error{{end}}" id="host" name="host" value="{{.host}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_DbHost}}ipt-error{{end}}" id="db_host" name="db_host" value="{{.db_host}}" />
</div> </div>
<div class="field"> <div class="field">
<label class="req" for="user">{{.i18n.Tr "install.user"}}</label> <label class="req" for="db_user">{{.i18n.Tr "install.user"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbUser}}ipt-error{{end}}" id="user" name="user" value="{{.user}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_DbUser}}ipt-error{{end}}" id="db_user" name="db_user" value="{{.db_user}}" />
</div> </div>
<div class="field"> <div class="field">
<label class="req" for="passwd">{{.i18n.Tr "install.password"}}</label> <label class="req" for="db_passwd">{{.i18n.Tr "install.password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DbPasswd}}ipt-error{{end}}" id="passwd" name="passwd" type="password" value="{{.passwd}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_DbPasswd}}ipt-error{{end}}" id="db_passwd" name="db_passwd" type="password" value="{{.db_passwd}}" />
</div> </div>
<div class="field"> <div class="field">
<label class="req" for="database_name">{{.i18n.Tr "install.db_name"}}</label> <label class="req" for="db_name">{{.i18n.Tr "install.db_name"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DatabaseName}}ipt-error{{end}}" id="database_name" name="database_name" value="{{.database_name}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_DbName}}ipt-error{{end}}" id="db_name" name="db_name" value="{{.db_name}}" />
<label></label> <label></label>
<span class="help">{{.i18n.Tr "install.db_helper"}}</span> <span class="help">{{.i18n.Tr "install.db_helper"}}</span>
</div> </div>
@ -51,8 +51,8 @@
</div> </div>
<div class="field sqlite-setting {{if not (eq .CurDbOption "SQLite3")}}hide{{end}}"> <div class="field sqlite-setting {{if not (eq .CurDbOption "SQLite3")}}hide{{end}}">
<label class="req" for="database_path">{{.i18n.Tr "install.path"}}</label> <label class="req" for="db_path">{{.i18n.Tr "install.path"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_DatabasePath}}ipt-error{{end}}" id="database_path" name="database_path" value="{{.database_path}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_DbPath}}ipt-error{{end}}" id="db_path" name="db_path" value="{{.db_path}}" />
<label></label> <label></label>
<span class="help">{{.i18n.Tr "install.sqlite_helper"}}</span> <span class="help">{{.i18n.Tr "install.sqlite_helper"}}</span>
</div> </div>
@ -61,8 +61,8 @@
<div class="text-center panel-desc">{{.i18n.Tr "install.general_title"}}</div> <div class="text-center panel-desc">{{.i18n.Tr "install.general_title"}}</div>
<div class="field"> <div class="field">
<label class="req" for="repo_path">{{.i18n.Tr "install.repo_path"}}</label> <label class="req" for="repo_root_path">{{.i18n.Tr "install.repo_path"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_RepoRootPath}}ipt-error{{end}}" id="repo_path" name="repo_path" value="{{.repo_path}}" required /> <input class="ipt ipt-large ipt-radius {{if .Err_RepoRootPath}}ipt-error{{end}}" id="repo_root_path" name="repo_root_path" value="{{.repo_root_path}}" required />
<label></label> <label></label>
<span class="help">{{.i18n.Tr "install.repo_path_helper"}}</span> <span class="help">{{.i18n.Tr "install.repo_path_helper"}}</span>
</div> </div>
@ -78,6 +78,12 @@
<label></label> <label></label>
<span class="help">{{.i18n.Tr "install.domain_helper"}}</span> <span class="help">{{.i18n.Tr "install.domain_helper"}}</span>
</div> </div>
<div class="field">
<label class="req" for="http_port">{{.i18n.Tr "install.http_port"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_HttpPort}}ipt-error{{end}}" id="http_port" name="http_port" value="{{.http_port}}" required />
<label></label>
<span class="help">{{.i18n.Tr "install.http_port_helper"}}</span>
</div>
<div class="field"> <div class="field">
<label class="req" for="app_url">{{.i18n.Tr "install.app_url"}}</label> <label class="req" for="app_url">{{.i18n.Tr "install.app_url"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AppUrl}}ipt-error{{end}}" id="app_url" name="app_url" value="{{.app_url}}" required /> <input class="ipt ipt-large ipt-radius {{if .Err_AppUrl}}ipt-error{{end}}" id="app_url" name="app_url" value="{{.app_url}}" required />
@ -93,12 +99,12 @@
<input class="ipt ipt-large ipt-radius {{if .Err_SmtpHost}}ipt-error{{end}}" id="smtp_host" name="smtp_host" value="{{.smtp_host}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_SmtpHost}}ipt-error{{end}}" id="smtp_host" name="smtp_host" value="{{.smtp_host}}" />
</div> </div>
<div class="field"> <div class="field">
<label for="mailer_user">{{.i18n.Tr "install.mailer_user"}}</label> <label for="smtp_user">{{.i18n.Tr "install.mailer_user"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_SmtpEmail}}ipt-error{{end}}" id="mailer_user" name="mailer_user" value="{{.mailer_user}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_SMTPEmail}}ipt-error{{end}}" id="smtp_user" name="smtp_user" value="{{.smtp_user}}" />
</div> </div>
<div class="field"> <div class="field">
<label for="mailer_pwd">{{.i18n.Tr "install.mailer_password"}}</label> <label for="smtp_pwd">{{.i18n.Tr "install.mailer_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_SmtpPasswd}}ipt-error{{end}}" id="mailer_pwd" name="mailer_pwd" type="password" value="{{.mailer_pwd}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_SMTPPasswd}}ipt-error{{end}}" id="smtp_pwd" name="smtp_pwd" type="password" value="{{.smtp_pwd}}" />
</div> </div>
<hr> <hr>
@ -122,12 +128,12 @@
<input class="ipt ipt-large ipt-radius {{if .Err_AdminName}}ipt-error{{end}}" id="admin_name" name="admin_name" value="{{.admin_name}}" required /> <input class="ipt ipt-large ipt-radius {{if .Err_AdminName}}ipt-error{{end}}" id="admin_name" name="admin_name" value="{{.admin_name}}" required />
</div> </div>
<div class="field"> <div class="field">
<label class="req" for="admin_pwd">{{.i18n.Tr "install.admin_password"}}</label> <label class="req" for="admin_passwd">{{.i18n.Tr "install.admin_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="admin_pwd" name="admin_pwd" type="password" value="{{.admin_pwd}}" required /> <input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="admin_passwd" name="admin_passwd" type="password" value="{{.admin_passwd}}" required />
</div> </div>
<div class="field"> <div class="field">
<label class="req" for="confirm_passwd">{{.i18n.Tr "install.confirm_password"}}</label> <label class="req" for="admin_confirm_passwd">{{.i18n.Tr "install.confirm_password"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="confirm_passwd" name="confirm_passwd" type="password" required /> <input class="ipt ipt-large ipt-radius {{if .Err_AdminPasswd}}ipt-error{{end}}" id="admin_confirm_passwd" name="admin_confirm_passwd" type="password" required />
</div> </div>
<div class="field"> <div class="field">
<label class="req" for="admin_email">{{.i18n.Tr "install.admin_email"}}</label> <label class="req" for="admin_email">{{.i18n.Tr "install.admin_email"}}</label>

View File

@ -32,7 +32,7 @@
{{end}} {{end}}
</td> </td>
<td class="sha"><a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td> <td class="sha"><a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
<td class="message"><span class="text-truncate">{{Str2html .Summary}}</span></td> <td class="message"><span class="text-truncate">{{RenderCommitMessage .Summary $.RepoLink}}</span></td>
<td class="date">{{TimeSince .Author.When $.Lang}}</td> <td class="date">{{TimeSince .Author.When $.Lang}}</td>
</tr> </tr>
{{end}} {{end}}

View File

@ -17,7 +17,7 @@
<div class="panel panel-info panel-radius diff-head-box"> <div class="panel panel-info panel-radius diff-head-box">
<div class="panel-header"> <div class="panel-header">
<a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a> <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a>
<h4 class="commit-message">{{Str2html .Commit.Message}}</h4> <h4 class="commit-message">{{RenderCommitMessage .Commit.Message $.RepoLink}}</h4>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<span class="pull-right"> <span class="pull-right">
@ -74,11 +74,11 @@
</ol> </ol>
</div> </div>
{{range .Diff.Files}} {{range $i, $file := .Diff.Files}}
<div class="panel panel-radius diff-file-box diff-box file-content" id="diff-{{.Index}}"> <div class="panel panel-radius diff-file-box diff-box file-content" id="diff-{{.Index}}">
<div class="panel-header"> <div class="panel-header">
<div class="diff-counter count pull-left"> <div class="diff-counter count pull-left">
{{if not .IsBin}} {{if not $file.IsBin}}
<span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span> <span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
<span class="bar"> <span class="bar">
<span class="pull-left add"></span> <span class="pull-left add"></span>
@ -90,9 +90,9 @@
{{end}} {{end}}
</div> </div>
<a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{$.SourcePath}}/{{.Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{$.SourcePath}}/{{.Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
<span class="file">{{.Name}}</span> <span class="file">{{$file.Name}}</span>
</div> </div>
{{$isImage := (call $.IsImageFile .Name)}} {{$isImage := (call $.IsImageFile $file.Name)}}
<div class="panel-body file-body file-code code-view code-diff"> <div class="panel-body file-body file-code code-view code-diff">
{{if $isImage}} {{if $isImage}}
<div class="text-center"> <div class="text-center">
@ -101,18 +101,18 @@
{{else}} {{else}}
<table> <table>
<tbody> <tbody>
{{range .Sections}} {{range $j, $section := $file.Sections}}
{{range .Lines}} {{range $k, $line := $section.Lines}}
<tr class="{{DiffLineTypeToStr .Type}}-code nl-1 ol-1"> <tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$i}} ol-{{$i}}">
<td class="lines-num lines-num-old"> <td class="lines-num lines-num-old">
<span rel="L1">{{if .LeftIdx}}{{.LeftIdx}}{{end}}</span> <span rel="diff-{{Add $i 1}}L{{$j}}{{$k}}">{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}</span>
</td> </td>
<td class="lines-num lines-num-new"> <td class="lines-num lines-num-new">
<span rel="L1">{{if .RightIdx}}{{.RightIdx}}{{end}}</span> <span rel="diff-{{Add $i 1}}L{{$j}}{{$k}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span>
</td> </td>
<td class="lines-code"> <td class="lines-code">
<pre>{{.Content}}</pre> <pre>{{$line.Content}}</pre>
</td> </td>
</tr> </tr>
{{end}} {{end}}

View File

@ -14,7 +14,7 @@
</span> </span>
<span class="last-commit"><a href="{{.RepoLink}}/commit/{{.LastCommit.Id}}" rel="nofollow"> <span class="last-commit"><a href="{{.RepoLink}}/commit/{{.LastCommit.Id}}" rel="nofollow">
<strong>{{ShortSha .LastCommit.Id.String}}</strong></a> <strong>{{ShortSha .LastCommit.Id.String}}</strong></a>
<span class="text-truncate">{{Str2html .LastCommit.Summary}}</span> <span class="text-truncate">{{RenderCommitMessage .LastCommit.Summary .RepoLink}}</span>
</span> </span>
<span class="age right">{{TimeSince .LastCommit.Author.When $.Lang}}</span> <span class="age right">{{TimeSince .LastCommit.Author.When $.Lang}}</span>
</th> </th>
@ -53,7 +53,7 @@
<a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}} ">{{SubStr $commit.Id.String 0 10}} </a> <a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}} ">{{SubStr $commit.Id.String 0 10}} </a>
</td> </td>
<td class="message"> <td class="message">
<span class="text-truncate">{{Str2html $commit.Summary}}</span> <span class="text-truncate">{{RenderCommitMessage $commit.Summary $.RepoLink}}</span>
</td> </td>
<td class="age">{{TimeSince $commit.Committer.When $.Lang}}</td> <td class="age">{{TimeSince $commit.Committer.When $.Lang}}</td>
</tr> </tr>

View File

@ -36,19 +36,21 @@
{{end}} {{end}}
</li> </li>
{{end}} {{end}}
<form action="{{AppSubUrl}}/user/settings/email" method="post"> </ul>
{{.CsrfTokenHtml}} <div class="panel-header">
<p class="panel-header"><strong>{{.i18n.Tr "settings.add_new_email"}}</strong></p> <strong>{{.i18n.Tr "settings.add_new_email"}}</strong>
<p class="field"> </div>
<form class="form form-align panel-body" id="add-email-form" action="{{AppSubUrl}}/user/settings/email" method="post">
{{.CsrfTokenHtml}}
<p class="field">
<label class="req" for="email">{{.i18n.Tr "email"}}</label> <label class="req" for="email">{{.i18n.Tr "email"}}</label>
<input class="ipt ipt-radius" id="email" name="email" type="text" required /> <input class="ipt ipt-large ipt-radius" id="email" name="email" type="text" required />
</p> </p>
<p class="field"> <p class="field">
<label></label> <label></label>
<button class="btn btn-green btn-radius" id="email-add-btn">{{.i18n.Tr "settings.add_email"}}</button> <button class="btn btn-green btn-large btn-radius" id="email-add-btn">{{.i18n.Tr "settings.add_email"}}</button>
</p> </p>
</form> </form>
</ul>
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@
<ul class="menu menu-vertical switching-list grid-1-5 left"> <ul class="menu menu-vertical switching-list grid-1-5 left">
<li {{if .PageIsSettingsProfile}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings">{{.i18n.Tr "settings.profile"}}</a></li> <li {{if .PageIsSettingsProfile}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings">{{.i18n.Tr "settings.profile"}}</a></li>
<li {{if .PageIsSettingsPassword}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/password">{{.i18n.Tr "settings.password"}}</a></li> <li {{if .PageIsSettingsPassword}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/password">{{.i18n.Tr "settings.password"}}</a></li>
<li {{if .PageIsSettingsEmail}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/email">{{.i18n.Tr "settings.emails"}}</a></li> <li {{if .PageIsSettingsEmails}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/email">{{.i18n.Tr "settings.emails"}}</a></li>
<li {{if .PageIsSettingsSSHKeys}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/ssh">{{.i18n.Tr "settings.ssh_keys"}}</a></li> <li {{if .PageIsSettingsSSHKeys}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/ssh">{{.i18n.Tr "settings.ssh_keys"}}</a></li>
<li {{if .PageIsSettingsSocial}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/social">{{.i18n.Tr "settings.social"}}</a></li> <li {{if .PageIsSettingsSocial}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/social">{{.i18n.Tr "settings.social"}}</a></li>
<li {{if .PageIsSettingsApplications}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/applications">{{.i18n.Tr "settings.applications"}}</a></li> <li {{if .PageIsSettingsApplications}}class="current"{{end}}><a href="{{AppSubUrl}}/user/settings/applications">{{.i18n.Tr "settings.applications"}}</a></li>